Ich möchte nur alle Dateien in einem bestimmten Verzeichnis in ein Bash-Array bringen (vorausgesetzt, keine der Dateien enthält eine neue Zeile im Namen):
Damit:
myarr=()
find . -maxdepth 1 -name "mysqldump*" | mapfile -t myarr; echo "${myarr[@]}"
Leeres Ergebnis!
Wenn ich auf Umwegen eine Datei verwende, vorübergehend oder auf andere Weise:
myarr=()
find . -maxdepth 1 -name "mysqldump*" > X
mapfile -t myarray < X
echo "${myarray[@]}"
Ergebnis!
Aber warum mapfile
liest man nicht richtig aus einer Pfeife?
find
undmapfile
hier überhaupt und nicht nur einfachmyarr=(mysqldump*)
? Dies funktioniert sogar mit Dateinamen mit Leerzeichen und Zeilenumbrüchen.nullglob
Option on (shopt -s nullglob
) aktivieren muss, ummyarr=(mysqldump*)
nicht mit dem Array zu enden,('mysqldump*')
falls keine Dateien übereinstimmen.Antworten:
Von
man 1 bash
:Solche Unterschalen erben Variablen von der Hauptschale, sind jedoch unabhängig. Dies bedeutet, dass
mapfile
in Ihrem ursprünglichen Befehl von selbst gearbeitet wirdmyarr
. Dannecho
(außerhalb des Rohrs) wird leer gedrucktmyarr
(das ist die Hauptschalemyarr
).Dieser Befehl funktioniert anders:
In diesem Fall
mapfile
undecho
arbeiten Sie auf der gleichenmyarr
(die nicht die Hauptschale istmyarr
).Um die Haupt-Shell zu ändern, müssen
myarr
Siemapfile
genau in der Haupt-Shell laufen . Beispiel:quelle
Bash führt die Befehle einer Pipeline in einer Subshell-Umgebung aus, sodass alle darin enthaltenen Variablenzuweisungen usw. für den Rest der Shell nicht sichtbar sind.
Dash (Debian
/bin/sh
) und Busyboxsh
sind ähnlich, während zsh und ksh den letzten Teil in der Haupt-Shell ausführen. In Bash können Sieshopt -s lastpipe
dasselbe tun, aber es funktioniert nur, wenn die Jobsteuerung deaktiviert ist, also nicht standardmäßig in interaktiven Shells.Damit:
(
read
undmapfile
haben das gleiche Problem.)Alternativ (und wie von Attie erwähnt) verwenden Sie die Prozessersetzung , die wie eine verallgemeinerte Pipe funktioniert und in Bash, ksh und zsh unterstützt wird.
POSIX lässt es nicht spezifiziert, ob die Teile einer Pipeline in Subshells ausgeführt werden oder nicht, daher kann nicht wirklich gesagt werden, dass eine der Shells darin "falsch" wäre.
quelle
set +m; shopt -s lastpipe; x=a; echo b | read x; echo $x; set -m
Wie Kamil betont hat, ist jedes Element in der Pipeline ein separater Prozess.
Sie können die folgende Prozessersetzung verwenden , um
find
in einem anderen Prozess ausgeführt zu werden, wobei dermapfile
Aufruf in Ihrem aktuellen Interpreter verbleibt und anschließend Zugriffmyarr
gewährt wird:b < <( a )
verhält sich ähnlicha | b
wie die Pipeline verdrahtet - der Unterschied besteht darin, dassb
" hier " ausgeführt wird.quelle