
Kurz gesagt möchte ich in einem Befehl die durch einen Befehl aufgelisteten Verzeichnisse verwenden find
:
find $(produces_dir_names --options...) -find-options...
Das Problem sind Leerzeichen in den Verzeichnisnamen. Ich dachte, es würde ausreichen, sie in der Ausgabe des erzeugenden Befehls (den ich ändern kann) in Anführungszeichen zu setzen:
"a" "a b" "a b c"
aber bash beschwert sich:
find: ‘"a"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b"’: No such file or directory
find: ‘"a’: No such file or directory
find: ‘b’: No such file or directory
find: ‘c"’: No such file or directory
Wie Sie sehen, bash
wird die Ausgabe des Befehls bei Leerzeichen aufgeteilt, sogar bei Anführungszeichen. Ich habe versucht, damit herumzuspielen IFS
und es auf einzustellen \n
, aber mein Verständnis davon scheint zu begrenzt, um es zum Laufen zu bringen.
Die einzige Problemumgehung, die ich gefunden habe, war in dieser Stack Overflow-Frage:
Bash-Befehlsersetzung entfernt Anführungszeichen, nämlich indem man ein eval
davor setzt, was aber irgendwie hässlich aussieht.
Meine Fragen:
Gibt es eine einfache Möglichkeit, diese Ersetzung ohne das zu schreiben, und wie würde es aussehen eval
?
Sind die Zitate überhaupt notwendig?
Beispiel (erzeugt dieselbe Ausgabe):
find $(echo '"a" "a b" "a b c"')
Antwort1
Vielleicht in zwei Zeilen
IFS=$'\n' DIRS=( $(produces_dir_names --options...) )
find "${DIRS[@]}" -find-options...
Beispiel:
$ mkdir -p "/tmp/test/a b/foo" "/tmp/test/x y/bar"
$ IFS=$'\n' DIRS=( $(printf "/tmp/test/a b\n/tmp/test/x y\n") )
$ find "${DIRS[@]}" -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar
Aber im Allgemeinen ist das kein guter Stil. Sie werden beispielsweise in Schwierigkeiten geraten, wenn Ihre DIRS Zeilenumbrüche enthalten. Korrigieren Sie besser Ihre „produces_dir_names“, um mit Nullbytes abgeschlossene Strings zu drucken. In meinem Beispiel würde das etwa so aussehen:
$ printf "/tmp/test/a b\0/tmp/test/x y\0" | xargs -0 -I '{}' find '{}' -mindepth 1
/tmp/test/a b/foo
/tmp/test/x y/bar
Wenn Sie „produces_dir_names“ nicht reparieren können, würde die allgemeinste Lösung bezüglich meines letzten Kommentars folgendermaßen aussehen:
produces_dir_names --options... | tr '\n' '\0' | xargs -0 -I '{}' find '{}' -find-options...
Es treten weiterhin Probleme mit „Newlines“ auf, sofern Sie „produces_dir_names“ nicht beheben, um dies zu vermeiden tr
.
Antwort2
Rudimeiers Antwortist gut – insbesondere der Teil über die Änderung produces_dir_names
zum Drucken nullterminierter Zeichenfolgen –, aber aus seiner Antwort geht möglicherweise nicht hervor, dass es einmal für jedes Verzeichnis ausgeführt wird . Wenn dies gut genug ist, ist es in Ordnung. Aber natürlich ist es möglich , mit mehreren Startpunkten find
aufzurufen ; z. B.find
finden dir 1 dir 2 dir 3 -Suchoptionen …
und aus der Frage geht hervor, dass Sie genau das wollen. Dies kann folgendermaßen erreicht werden:
printf "a\0a b\0a b c" | xargs -0 sh -c 'finde "$@" -Suchoptionen …' Sch
Dies führt xargs
zu einem einmaligen Aufruf sh -c
, wobei alle Verzeichnisnamen an den Befehl angehängt werden. Die Shell erweitert dann "$@"
die Liste dieser Verzeichnisnamen.
PS: Wenn produces_dir_names
zu viele Verzeichnisnamen aufgelistet werden, um sie in eine Befehlszeile zu packen, xargs
müssen mehrere Befehle erstellt werden. Verwenden Sie diese Option, xargs --verbose
um zu sehen, welche Befehle xargs
erstellt werden.
Antwort3
Um das Rätsel um die Fehlermeldungen, die Sie erhalten, aufzuklären:
find: ‘"a"’: No such file or directory find: ‘"a’: No such file or directory find: ‘b"’: No such file or directory find: ‘"a’: No such file or directory find: ‘b’: No such file or directory find: ‘c"’: No such file or directory
Die Antwort ist, dassDie Bash-Anführungszeichenentfernung entfernt keine Anführungszeichen, dieresultiertedurch Befehlsersetzung.
AusLESS='+/^ *Quote Removal' man bash
Quote Removal After the preceding expansions, all unquoted occurrences of the charac- ters \, ', and " that did not result from one of the above expansions are removed.
Zu den referenzierten „vorhergehenden Erweiterungen“ gehören:
EXPANSION Brace Expansion Tilde Expansion Parameter Expansion Command Substitution Arithmetic Expansion Process Substitution Word Splitting Pathname Expansion Quote Removal