Bash: Pipe 'Find' Ausgabe in 'Readarray'

12

Ich versuche, mit Dateien nach Dateien zu suchen findund diese Dateien in ein Bash-Array zu legen, damit ich andere Operationen an ihnen ausführen kann (z . B. lsoder grepsie). Aber ich kann nicht herausfinden, warum readarraydie findAusgabe nicht gelesen wird, wenn sie in sie geleitet wird.

Angenommen, ich habe zwei Dateien im aktuellen Verzeichnis file1.txtund file2.txt. Die findAusgabe ist also wie folgt:

$ find . -name "file*"
./file1.txt
./file2.txt

Also möchte ich das in ein Array leiten, dessen zwei Elemente die Zeichenfolgen sind "./file1.txt"und "./file2.txt"(natürlich ohne Anführungszeichen).

Ich habe dies unter anderem versucht:

$ declare -a FILES
$ find . -name "file*" | readarray FILES
$ echo "${FILES[@]}"; echo "${#FILES[@]}"

0

Wie Sie der echoAusgabe entnehmen können, ist mein Array leer.

Was genau mache ich hier falsch? Warum wird die Ausgabe nicht als Standardeingabe readarraygelesen findund diese Zeichenfolgen in das Array eingefügt?

villapx
quelle

Antworten:

19

Bei Verwendung einer Pipeline führt bash die Befehle in Subshells aus. Daher wird das Array gefüllt, jedoch in einer Subshell, sodass die übergeordnete Shell keinen Zugriff darauf hat.

Prozesssubstitution verwenden:

readarray FILES < <(find)

Beachten Sie, dass dies bei Dateien mit Zeilenumbrüchen im Namen nicht funktioniert. Wenn dies der Fall sein könnte, benötigen Sie eine ausgefeiltere Syntax:

readarray -d '' < <(find -print0)
Choroba
quelle
3
Um Newlines zu unterstützen, ist dies ausreichend:readarray -d '' < <(find your_args -print0)
VasyaNovikov
6

Die richtige Lösung ist:

unset a; declare -a a
while IFS= read -r -u3 -d $'\0' file; do
    a+=( "$file" )        # or however you want to process each file
done 3< <(find /tmp -type f -print0)

Das ähnelt dem, was Gregs BashFAQ 020 ausführlich erklärt, und diese Antwort behandelt .

Hat kein Problem mit ungeraden benannten Dateien (die kein NUL im Namen enthalten), mit Leerzeichen oder neuen Zeilen. Das Ergebnis wird in einem Array festgelegt, das für die weitere Verarbeitung nützlich ist.

Gemeinschaft
quelle
Großartig, dies ist eine bessere Lösung für das Problem, das ich zuerst lösen wollte. +1 sobald mein Repräsentant 15 erreicht :)
villapx
3

readarray kann auch von stdin lesen

readarray FILES <<< "$(find . -name "file*")"; echo "${#FILES[@]}"
smac89
quelle
Dies funktioniert nicht find -print0zum Schutz vor "unerwarteten" Dateinamen.
Roaima