Bash: Anführungszeichen bei Befehlsersetzung

Bash: Anführungszeichen bei Befehlsersetzung

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, bashwird die Ausgabe des Befehls bei Leerzeichen aufgeteilt, sogar bei Anführungszeichen. Ich habe versucht, damit herumzuspielen IFSund 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 evaldavor 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 findaufzurufen ; 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 xargszu 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_nameszu viele Verzeichnisnamen aufgelistet werden, um sie in eine Befehlszeile zu packen, xargsmüssen mehrere Befehle erstellt werden. Verwenden Sie diese Option, xargs --verboseum zu sehen, welche Befehle xargserstellt 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

verwandte Informationen