Readarray (oder Pipe) Problem

19

Ich blieb bei einem merkwürdigen readarrayKommandoverhalten.

Die man bashStaaten:

readarray
     Read lines from the standard input into the indexed array variable array

Aber diese Skripte funktionieren nicht (Array ist leer):

unset arr; (echo a; echo b; echo c) | readarray arr; echo ${#arr[@]}
unset arr; cat /etc/passwd | readarray arr;  echo ${#arr[@]}

Und diese Arbeit:

unset arr; readarray arr < /etc/passwd ;  echo ${#arr[@]}
unset arr; mkfifo /tmp/fifo; (echo a; echo b; echo c) > /tmp/fifo & mapfile arr < /tmp/fifo ; echo ${#arr[@]}

Was ist los mit Pipe?

dchirikov
quelle

Antworten:

15

Vielleicht versuchen Sie:

unset arr
printf %s\\n a b c | {
    readarray arr
    echo ${#arr[@]}
}

Ich gehe davon aus, dass es funktionieren wird, aber sobald Sie den letzten {Shell- ; }Kontext am Ende der |Pipeline verlassen, verlieren Sie Ihren Variablenwert. Dies liegt daran, dass jeder der |separaten |Prozesse in einer |Pipeline in einer (Subshell ausgeführt wird ). Dein Ding funktioniert also nicht aus dem gleichen Grund:

( arr=( a b c ) ) ; echo ${arr[@]}

... nicht - der Variablenwert wurde in einem anderen Shell-Prozess als dem festgelegt, in dem Sie ihn aufrufen.

mikeserv
quelle
23

readarrayVerwenden Sie entweder die Prozessersetzung anstelle der Pipeline, um sicherzustellen, dass der Befehl in der aktuellen Shell ausgeführt wird:

readarray arr < <( echo a; echo b; echo c )

oder (wenn bash4.2 oder neuer) benutze die lastpipeShell Option:

shopt -s lastpipe
( echo a; echo b; echo c ) | readarray arr
chepner
quelle
1
Cool. Das funktioniert, aber was genau ist Prozesssubstitution? Und was bedeutet es, < <2 Pfeile zu haben ?
CMCDragonkai
1
Siehe die bashManpage. Kurz gesagt, es handelt sich um eine Syntax zur Behandlung einer Pipeline als Dateideskriptor. < <(...)bedeutet, die Eingabe (die erste <) von der Ausgabe des Befehls nach innen umzuleiten <(...). In ähnlicher Weise > >(...)würde die Standardausgabe an die Standardeingabe der internen Pipeline übergeben >(...). Sie müssen die Umleitung nicht unbedingt für die Prozessersetzung verwenden. cat <( echo a b c )funktioniert auch.
Chepner
Beide Optionen führen für mich zu einem unerwünschten Ergebnis, bei dem jedes Array-Element die Zeilenenden am Ende jeder Zeichenfolge beibehält. Während die Antwort von smac89 dieses Problem nicht hat.
Thnee
3

readarray kann auch von stdin lesen, also:

readarray arr <<< "$(echo a; echo b; echo c)"; echo ${#arr[@]}
smac89
quelle