problema readarray (o pipe)

Sono rimasto bloccato con uno strano comportamento del comando readarray.

Il man bash afferma:

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

ma questi script non funzionano (larray è vuoto):

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

E questi funzionano:

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[@]} 

Cosa cè di sbagliato in pipe?

Risposta

Forse prova:

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

Mi aspetto che funzioni , ma nel momento in cui esci dallultimo contesto { shell ; } alla fine del | pipeline lì perderai il valore della variabile. Questo perché ciascuno dei | | processi separati allinterno di una | pipeline viene eseguito in una ( subshell ). Quindi la tua cosa non funziona per lo stesso motivo:

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

… non “t – il valore della variabile è stato impostato in un diverso processo della shell rispetto a quello in cui lo chiami.

Rispondi

Per assicurarti che readarray il comando viene eseguito nella shell corrente, o utilizza la sostituzione del processo al posto della pipeline:

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

o (se bash 4.2 o versione successiva) utilizza lastpipe opzione della shell:

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

Commenti

  • Fantastico. Funziona, ma cosè esattamente la sostituzione del processo? E cosa significa avere < < 2 frecce?
  • Vedere la pagina man di bash. In breve, è ' la sintassi per trattare una pipeline come un descrittore di file. < <(...) significa reindirizzare linput (il primo <) dalloutput del comando allinterno di <(...). Allo stesso modo, > >(...) passerebbe lo standard output allo standard input della pipeline allinterno di >(...). Non è necessario ' utilizzare il reindirizzamento con sostituzione del processo. Anche cat <( echo a b c ) funziona.
  • Entrambe queste opzioni producono un risultato indesiderato per me, in cui ogni elemento dellarray mantiene le terminazioni di riga alla fine di ogni stringa. Mentre la risposta di smac89 non presenta questo problema.
  • Le terminazioni di riga possono essere rimosse utilizzando readarray -t arr. Da man bash: -t Remove a trailing newline from each line read.
  • I ' m utilizzando bash 5.0.17 e questo ' non funziona per me. ' ho anche controllato BASHOPTS e contiene lastpipe, ma cat myfile.txt | readarray -t arr restituisce un arr, ma readarray -t arr < <(cat myfile.txt) funziona correttamente.

Risposta

readarray può leggere anche da stdin, quindi:

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *