Readarray- (oder Pipe-) Problem

Ich habe mich an ein seltsames Verhalten des Befehls readarray gehalten.

In man bash heißt es:

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 funktionieren:

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 mit der Pipe falsch?

Antwort

Vielleicht versuchen Sie:

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

Ich gehe davon aus, dass es funktionieren wird , aber in dem Moment, in dem Sie aus dieser letzten { Shell ; } -Kontext am Ende des | Pipeline dort verlieren Sie Ihren Variablenwert. Dies liegt daran, dass jeder der | separaten | -Prozesse innerhalb einer | -Pipeline in ausgeführt wird eine ( Subshell ). Ihr Ding funktioniert also aus demselben Grund nicht:

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

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

Antwort

Um sicherzustellen, dass wird in der aktuellen Shell ausgeführt. Verwenden Sie entweder die Prozessersetzung anstelle der Pipeline:

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

oder (wenn bash 4.2 oder höher) Verwenden Sie die Shell-Option lastpipe:

shopt -s lastpipe ( echo a; echo b; echo c ) | readarray -t arr 

Kommentare

  • Cool. Das funktioniert, aber was genau ist Prozesssubstitution? Und was bedeutet es, < < 2 Pfeile zu haben?
  • Siehe die Manpage bash. Kurz gesagt, es ist die Syntax von ' zum Behandeln einer Pipeline als Dateideskriptor. < <(...) bedeutet, dass Eingaben (die erste <) von der Ausgabe des Befehls innerhalb von <(...). Ähnlich würde > >(...) die Standardausgabe an die Standardeingabe der Pipeline innerhalb von >(...) übergeben. ' muss nicht unbedingt die Umleitung mit Prozessersetzung verwenden. cat <( echo a b c ) funktioniert auch.
  • Diese beiden 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.
  • Zeilenenden können mit readarray -t arr entfernt werden. Von man bash: -t Remove a trailing newline from each line read.
  • Ich ' m benutze bash 5.0.17 und dies funktioniert bei mir nicht '. Ich ' habe sogar BASHOPTS überprüft und es enthält lastpipe, aber cat myfile.txt | readarray -t arr gibt ein leeres arr aus, aber readarray -t arr < <(cat myfile.txt) funktioniert ordnungsgemäß.

Antwort

readarray kann auch von stdin lesen, also:

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

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.