Läsarray (eller rör) utgåva

Jag höll mig med ett konstigt beteende av readarray kommando.

man bash anger:

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

men dessa skript fungerar inte (arrayen är tom):

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

Och dessa fungerar:

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

Vad är det för fel på röret?

Svar

Kanske försök:

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

Jag förväntar mig att det kommer att fungera , men när du går ut ur det sista { skalet ; } -kontext i slutet av | pipeline där kommer du att förlora ditt variabla värde. Detta beror på att var och en av | separata | processer inom en | pipeline körs i a ( subshell ). Så din grej fungerar inte av samma anledning:

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

… fungerar inte – variabelvärdet sattes i en annorlunda skalprocess än den där du anropar den.

Svar

För att säkerställa att readarray kommandot körs i det aktuella skalet, använd antingen processersättning istället för pipelinen:

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

eller (om bash 4.2 eller senare) använder lastpipe skalalternativet:

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

Kommentarer

  • Cool. Detta fungerar, men vad exakt är processersättning? Och vad betyder det att ha < < 2 pilar?
  • Se bash mansidan. Kort sagt ' s syntax för att behandla en pipeline som en filbeskrivare. < <(...) betyder att omdirigera ingång (den första <) från kommandos utgång inuti <(...). På samma sätt skulle > >(...) skicka standardutdata till standardingången för rörledningen inuti >(...). Du behöver inte ' nödvändigtvis använda omdirigering med processersättning. cat <( echo a b c ) fungerar också.
  • Båda dessa alternativ ger ett oönskat resultat för mig, där varje arrayobjekt behåller radändarna i slutet av varje sträng. Medan svaret från smac89 inte har detta problem.
  • Linjeändar kan avlägsnas med readarray -t arr. Från man bash: -t Remove a trailing newline from each line read.
  • I ' m med bash 5.0.17 och detta fungerar inte ' för mig. Jag ' har även markerat BASHOPTS och den innehåller lastpipe, ändå cat myfile.txt | readarray -t arr ger en tom arr, men readarray -t arr < <(cat myfile.txt) fungerar korrekt.

Svar

readarray kan också läsas från stdin, så:

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

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *