Ich bin relativ neu in Bash und versuche, etwas zu tun, das auf den ersten Blick ziemlich einfach zu sein schien - führen Sie find über eine Verzeichnishierarchie aus, um alle * .wma-Dateien abzurufen, und leiten Sie diese Ausgabe an einen Befehl weiter, in dem ich sie in mp3 und konvertiere Speichern Sie die konvertierte Datei als .mp3. Meiner Meinung nach sollte der Befehl wie folgt aussehen (ich habe den Befehl zur Audiokonvertierung weggelassen und verwende stattdessen Echo zur Veranschaulichung):
$ find ./ -name '*.wma' -type f -print0 | xargs -0 -I f echo ${f%.*}.mp3
So wie ich es verstehe, kann ich mit dem Argument -print0 Dateinamen mit Leerzeichen verarbeiten (was viele davon tun, da es sich um Musikdateien handelt). Ich erwarte dann (als Ergebnis von xargs), dass jeder Dateipfad von find in f erfasst wird und dass ich unter Verwendung der Teilzeichenfolge match / delete am Ende der Zeichenfolge den ursprünglichen Dateipfad mit einer MP3-Datei wiedergeben sollte Erweiterung statt wma. Anstelle dieses Ergebnisses sehe ich jedoch Folgendes:
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
...
Meine Frage (abgesehen von der spezifischen Frage, was ich hier falsch mache) lautet also: Müssen Werte, die das Ergebnis einer Pipe-Operation sind, bei String-Manipulationsoperationen anders behandelt werden als diejenigen, die das Ergebnis einer Variablenzuweisung sind ?
xargs
mit zu verwendenfind
. Es kommt mit einer-exec
Option. Können Sie Ihrer Frage einfach den Befehl hinzufügen, den Sie verwenden möchten, und jemand kann Ihnen den richtigenfind
Befehl zeigen?{}
Mitglied)xargs
besser geeignet ist alsexec
. Ein Beispiel hierfür finden Sie in diesem Stackpost stackoverflow.com/questions/896808/find-exec-cmd-vs-xargs .Antworten:
Wie andere Antworten bereits identifiziert haben,
${f%.*}
wird diese von der Shell erweitert, bevor sie denxargs
Befehl ausführt. Sie müssen diese Erweiterung für jeden Dateinamen einmal ausführen, wobei die Shell-Variablef
auf den Dateinamen festgelegt ist (Übergabe-I f
funktioniert nicht: Hatxargs
keine Vorstellung von einer Shell-Variablen, sucht nach der Zeichenfolgef
im Befehl, wenn Sie dies möchten verwendet zBxargs -I e echo …
hätte es Befehle wie./somedir/somefile.wmacho .mp3
) ausgeführt.Wenn Sie diesen Ansatz beibehalten
xargs
, rufen Sie an, eine Shell aufzurufen, die die Erweiterung ausführen kann. Besser, sagenfind
-xargs
ist ein weitgehend veraltetes Werkzeug und schwer richtig zu verwenden, da moderne Versionen von find ein Konstrukt haben, das die gleiche Aufgabe (und mehr) mit weniger Installationsschwierigkeiten erledigt. Stattfind … -print0 | xargs -0 command …
laufenfind … -exec command … {} +
.Das Argument
_
ist$0
in der Shell; Die Dateinamen werden als Positionsargumente übergeben, die sich in einerfor f; do …
Schleife befinden. Eine einfachere Version dieses Befehls führt für jede Datei eine separate Shell aus, die äquivalent, aber etwas langsamer ist:Sie müssen es hier eigentlich nicht verwenden
find
, vorausgesetzt, Sie führen eine relativ neue Shell aus (ksh93, bash ≥4.0 oder zsh). Geben Sie in bashshopt -s globstar
your ein.bashrc
, um das**/
Glob-Muster für die Rekursion in Unterverzeichnissen zu aktivieren (in ksh alsoset -o globstar
). Dann kannst du rennen(Wenn Sie Verzeichnisse aufgerufen haben
*.wma
, fügen Sie diese[ -f "$f" ] || continue
am Anfang der Schleife hinzu.)quelle
Bei Ihrer Lösungsbewertung von $ {f%. *}. Mp3 wird in der Shell ausgeführt, in der Sie den gesamten Befehl aufrufen, nicht in der von den xargs gegabelten Shell . Und in Ihrer Shell gibt es keine f- Variable, sie wird durch eine leere Zeichenfolge ersetzt.
Lösung mit xargs mit -I f :
Aber ich würde es so machen:
quelle