Die Situation ist, ich habe einen MP3-Player mpg321
, der eine Liste von Dateien als Argument akzeptiert. Ich bewahre meine Musik in einem Verzeichnis mit dem Namen "Musik" auf, in dem sich noch einige Verzeichnisse befinden. Ich möchte nur alle spielen, also starte ich das Programm mit
mpg321 $(find /music -iname "*\.mp3")
. Das Problem ist, dass einige Dateinamen Leerzeichen enthalten und das Programm diese Namen in kleinere Teile zerlegt und sich über fehlende Dateien beschwert. Das Ergebnis find
in Anführungszeichen setzen
mpg321 "$(find /music -iname "*\.mp3")"
hilft nicht, weil alle zu einem großen "Dateinamen" werden, der offensichtlich nicht gefunden wird.
Wie kann ich das dann machen? Wenn das wichtig ist, verwende ich bash
, werde aber zsh
bald wechseln .
quelle
mpg321 $(find /music -iname "*\.mp3" -print0)
nicht?mpg321
hat nichts damit zu tun, es ist die Shell, die die Ausgabe vonfind
in separate Argumente aufteilt . Und-print0 | xargs -0
funktioniert mit jedem möglichen Dateinamen.Mit GNU find können Sie auch
-print0
und verwendenxargs -0
, aber es macht wenig Sinn, noch ein anderes Tool zu lernen. Die-exec ... {} +
Syntax wird kaum erwähnt, da Linux sie später erworben hat-print0
, aber es gibt keinen Grund, sie jetzt nicht zu verwenden.Mit zsh oder bash 4 ist dies viel einfacher:
Nur in zsh können Sie ein (Teil eines) Musters unabhängig von Groß- und Kleinschreibung machen:
quelle
Ich denke, Stevens Lösung ist die beste, aber eine andere Möglichkeit besteht darin, das xargs-
-I
Flag zu verwenden, mit dem Sie eine Zeichenfolge angeben können, die dann im Befehl durch das Argument ersetzt wird (anstatt das Argument nur an das Ende des Befehls anzuhängen). Sie können das verwenden, um das Argument zu zitieren:quelle
-0
Flagge von xargs ohne die von find-print0
. Auch die-I
Flagge von xargs hat eine Reihe von Konsequenzen. Im Gegensatz zu einfach, beixargs
dem alle Zeilen von stdin zu einem Befehl komprimiert werden,xargs -I
wird esmpg321
möglicherweise hunderte oder tausende Male ausgeführt (einmal für jede Datei), was sicherlich nicht beabsichtigt ist. Denken Sie auch daran, dass das Zitieren von foo nichtxargs
erforderlich ist, wie dies intern der Fall ist. Beachten Sie, dass alle Dateinamenxargs -I
nicht geöffnet werden, wenn Sie sie in einer Zeile komprimieren und an diese senden .Es ist in der Regel am besten direkt ,
-exec ${tgt_process} \{\} +
aber wenn Sie tun müssen eine zuverlässig getrennte Liste von Dateinamen in einer Datei oder einem Stream bekommen ausfind
welchen Gründen auch immer, dann können Sie dies tun:Was Sie daraus machen, sind zwei einzigartige Zeichenfolgen. Am Anfang jedes Dateinamens steht die Zeichenfolge
\n///
und am Ende jedes Dateinamens steht die Zeichenfolge///\n
. Diese beiden Zeichenfolgen kommen nirgendwo anders infind
der Ausgabe vor, außer an diesen Positionen, unabhängig davon, welche Zeichen die Dateinamen enthalten.Darüber hinaus ist die oben genannte Verwendung POSIX Portable Baseline und kann für nahezu jedes Unix-System verwendet werden. Dies gilt nicht für die Verwendung eines Null-Byte-Begrenzers - trotz seiner Bequemlichkeit -, die von einigen anderen empfohlen wird.
Aber auch dies ist nur notwendig, wenn Sie aus irgendeinem Grund nicht direkt
-exec
Ihre können$tgt_process
, da dies Ihr Ziel sein sollte. Zum einen erfordert die obige Methode immer noch das Parsen. Wenn Sie beispielsweise möchten, dass jede Dateinamen-Shell in Anführungszeichen gesetzt wird, müssen Sie zuerst sicherstellen, dass alle harten Anführungszeichen im Dateinamen maskiert werden:Dadurch wird ein ordnungsgemäß Shell-Escape-Array von Dateinamen ausgegeben, unabhängig davon, welche Zeichen sie enthalten. Jetzt müssen Sie nur noch hoffen, dass Ihre Bewerbung auf der Empfängerseite sie nicht beschädigt.
quelle
Eine andere Möglichkeit besteht darin, alle Sonderzeichen, die in Ihren Dateinamen enthalten sind, zu umgehen. Z.B:
Dadurch werden die ordnungsgemäß maskierten Dateinamen zur Ausführung an xargs übergeben, und es treten keine Probleme auf.
quelle
sed 's|.|\\&|g'
- das empfiehlt POSIX sowieso.