Warum funktioniert dieser xargs-Befehl nicht?

14

Ich wollte alle .sh-Erweiterungen löschen.

ls *.sh | xargs -I {} mv {} `basename {} .sh`

Es funktioniert jedoch nicht, sondern basenamegibt einen unveränderten Dateinamen zurück.

Warum verhält es sich so?

Das funktioniert zum Beispiel:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;

EDIT :

Lösung: Ein einfaches Anführungszeichen verhindert die `basename ...`Auswertung durch die Shell, bevor der Befehl ausgeführt wird.

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'
Majkinetor
quelle

Antworten:

12

Weil der Befehl basename ausgeführt wird, bevor die Pipeline ausgeführt wird. Damit dies funktioniert, benötigen Sie xargs, um basename auszuführen, und das können Sie sh -czB mit:

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy

Anmerkungen:

  • Wenn Sie nicht angeben, xargswo die Dateinamen eingefügt werden sollen, werden sie am Ende der Befehlszeile hinzugefügt.
  • Sie sollten den -L1Schalter oder dessen Äquivalent verwenden, sodass xargsnur ein Argument an übergeben wird sh.
  • Die Verwendung der Ausgabe von lskann unerwünschte Auswirkungen haben .

Bearbeiten

Veraltete Optionen wurden entfernt, dank TechZilla

Thor
quelle
3
Ihr erster Punkt ist falsch, es sei denn, Sie meinen, er ist standardmäßig für die -iOption eingestellt, aber diese "klassischen" Optionen sind veraltet. Um beispielsweise nur eine Option / Zeile zu verwenden, empfiehlt die neue POSIX-Manpage -L1. Um das alte Verhalten von aufzurufen -i, empfiehlt die Seite die -I'{}'Option.
JM Becker
Es geht also eigentlich um "" statt "" Symbole. Ich denke 'verhindert die Shell-Auswertung von ``. Siehe meine Änderungen.
Majkinetor
@ TechZilla: danke für die korrekturen. @majkinetor: ja und nein, du musst die Auswertung verzögern, aber ich glaube nicht, dass du Backticks (`) verwenden kannst.
Thor
1
@majkinetor: ah, ich verstehe was du jetzt meinst. Zum Umbenennen von Dateien auf diese Weise würde ich eher verwenden rename, zum Beispiel: rename 's/\.sh//' *.sh. Versuchen Sie es zuerst mit Trockenlauf ( -n).
Thor
1
@majkinetor: rename großartig und ziemlich einfach, aber denke daran, dass es sehr vertriebsspezifisch ist. RHEL- und Debian-basierte Distributionen bieten unterschiedliche renameBefehle, daher muss man dies berücksichtigen, wenn man Cross-Distribution-Skripte erstellt.
JM Becker
4

Ich bin mir nicht sicher, warum Ihre erste Zeile nicht funktioniert. Oder suchen Sie nach einer geeigneten Methode, um alle .sh-Dateien umzubenennen?

Angenommen, es ist die sauberste Methode, bevorzuge ich, Befehlsoptionen vorzubereiten xargs. Zum Entfernen einer .sh-Dateierweiterung halte ich oft diesen Ansatz,

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
JM Becker
quelle