Update 2020 für Linux-Benutzer:
Wenn Sie eine aktuelle Version von bash (4.4-alpha oder besser) haben, wie Sie es wahrscheinlich unter Linux tun, sollten Sie die Antwort von Benjamin W. verwenden .
Wenn Sie unter Mac OS arbeiten, das - wie ich zuletzt überprüft habe - immer noch Bash 3.2 verwendet oder anderweitig ein älteres Bash verwendet, fahren Sie mit dem nächsten Abschnitt fort.
Antwort für Bash 4.3 oder früher
Hier ist eine Lösung, um die Ausgabe von findin ein bashArray zu bekommen:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
Dies ist schwierig, da Dateinamen im Allgemeinen Leerzeichen, neue Zeilen und andere skriptfeindliche Zeichen enthalten können. Die einzige Möglichkeit, finddie Dateinamen zu verwenden und sicher voneinander zu trennen, besteht darin, -print0die mit einem Nullzeichen getrennten Dateinamen zu drucken. Dies würde nicht viel von einem Nachteil sein , wenn bash readarray/ mapfileFunktionen null getrennte Zeichenketten unterstützt , aber sie tun es nicht. Bash's readtut es und das führt uns zu der Schleife oben.
[Diese Antwort wurde ursprünglich im Jahr 2014 geschrieben. Wenn Sie eine aktuelle Version von Bash haben, lesen Sie bitte das Update unten.]
Wie es funktioniert
Die erste Zeile erstellt ein leeres Array: array=()
Jedes Mal, wenn die readAnweisung ausgeführt wird, wird ein durch Null getrennter Dateiname aus der Standardeingabe gelesen. Die -rOption weist readan, Backslash-Zeichen in Ruhe zu lassen. Das -d $'\0'teilt mit, readdass die Eingabe durch Null getrennt wird. Da wir den Namen auf weglassen, readsetzt die Shell die Eingabe in den Standardnamen : REPLY.
Die array+=("$REPLY")Anweisung hängt den neuen Dateinamen an das Array an array.
Die letzte Zeile kombiniert Umleitung und Befehlssubstitution, um die Ausgabe findan die Standardeingabe der whileSchleife bereitzustellen .
Warum Prozesssubstitution verwenden?
Wenn wir keine Prozessersetzung verwenden würden, könnte die Schleife wie folgt geschrieben werden:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
Oben wird die Ausgabe von findin einer temporären Datei gespeichert und diese Datei wird als Standardeingabe für die while-Schleife verwendet. Die Idee der Prozessersetzung besteht darin, solche temporären Dateien unnötig zu machen. Anstatt dass die whileSchleife ihren Standard erhält tmpfile, können wir sie auch ihren Standard erhalten lassen <(find . -name ${input} -print0).
Prozesssubstitution ist weithin nützlich. An vielen Stellen, an denen ein Befehl aus einer Datei lesen möchte , können Sie <(...)anstelle eines Dateinamens die Prozessersetzung angeben . Es gibt eine analoge Form, >(...)die anstelle eines Dateinamens verwendet werden kann, in den der Befehl in die Datei schreiben möchte .
Wie Arrays ist die Prozessersetzung ein Merkmal von Bash und anderen fortgeschrittenen Shells. Es ist nicht Teil des POSIX-Standards.
Alternative: Lastpipe
Falls gewünscht, lastpipekann anstelle der Prozesssubstitution verwendet werden (Hutspitze: Caesar ):
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipeweist bash an, den letzten Befehl in der Pipeline in der aktuellen Shell auszuführen (nicht den Hintergrund). Auf diese Weise arraybleibt das nach Abschluss der Pipeline bestehen. Da lastpipedie Jobsteuerung nur wirksam wird, werden sie ausgeführt set +m. (In einem Skript ist die Jobsteuerung im Gegensatz zur Befehlszeile standardmäßig deaktiviert.)
Zusätzliche Bemerkungen
Der folgende Befehl erstellt eine Shell-Variable, kein Shell-Array:
array=`find . -name "${input}"`
Wenn Sie ein Array erstellen möchten, müssen Sie Parens um die Ausgabe von find setzen. Naiv könnte man also:
array=(`find . -name "${input}"`)
Das Problem ist, dass die Shell eine Wortaufteilung für die Ergebnisse von durchführt, findsodass nicht garantiert wird, dass die Elemente des Arrays Ihren Wünschen entsprechen.
Update 2019
Ab Version 4.4-alpha unterstützt bash jetzt eine -dOption, sodass die obige Schleife nicht mehr erforderlich ist. Stattdessen kann man verwenden:
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
Weitere Informationen hierzu finden Sie (und upvote) Benjamin W. Antwort .