readarray (of pipe) probleem

Ik bleef bij een vreemd gedrag van readarray commando.

De man bash zegt:

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

maar deze scripts werken niet (array is leeg):

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

En deze werken:

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

Wat is er mis met pipe?

Antwoord

Probeer misschien:

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

Ik verwacht dat het zal werken , maar op het moment dat u uit die laatste { shell ; } context stapt aan het einde van de | pipeline daar verlies je je variabele waarde. Dit komt doordat elk van de | afzonderlijke | processen binnen een | -pijplijn wordt uitgevoerd in een ( subshell ). Dus jouw ding werkt niet om dezelfde reden:

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

… niet “t – de waarde van de variabele is ingesteld in een verschillende shell-proces dan degene waarin u het aanroept.

Answer

Om ervoor te zorgen dat de readarray commando wordt uitgevoerd in de huidige shell, ofwel gebruik procesvervanging in plaats van de pijplijn:

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

of (if bash 4.2 of hoger) gebruik de lastpipe shell-optie:

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

Reacties

  • Cool. Dit werkt, maar wat is procesvervanging precies? En wat betekent het om < < 2 pijlen te hebben?
  • Zie de bash man-pagina. Kortom, het is de ' syntaxis voor het behandelen van een pijplijn als een bestandsdescriptor. < <(...) betekent het omleiden van invoer (de eerste <) van de uitvoer van de opdracht binnen <(...). Op dezelfde manier zou > >(...) standaarduitvoer doorgeven aan de standaardinvoer van de pijplijn binnen >(...). U hoeft niet ' per se omleiding te gebruiken met procesvervanging. cat <( echo a b c ) werkt ook.
  • Beide opties produceren een ongewenst resultaat voor mij, waarbij elk array-item de regeleinde aan het einde van elke string behoudt. Terwijl het antwoord van smac89 dit probleem niet heeft.
  • Regeluitgangen kunnen worden verwijderd met readarray -t arr. Van man bash: -t Remove a trailing newline from each line read.
  • Ik ' m gebruik bash 5.0.17 en dit ' werkt niet voor mij. Ik ' heb zelfs BASHOPTS gecontroleerd en het bevat lastpipe, maar cat myfile.txt | readarray -t arr geeft een lege arr, maar readarray -t arr < <(cat myfile.txt) werkt correct.

Answer

readarray kan ook lezen van stdin, dus:

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

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *