Utknąłem z dziwnym zachowaniem polecenia readarray.
man bash stwierdza:
readarray Read lines from the standard input into the indexed array variable array
, ale te skrypty nie działają (tablica jest pusta):
unset arr; (echo a; echo b; echo c) | readarray arr; echo ${#arr[@]} unset arr; cat /etc/passwd | readarray arr; echo ${#arr[@]}
I to działa:
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[@]}
Co jest nie tak z potokiem?
Odpowiedź
Może spróbuj:
unset arr printf %s\\n a b c | { readarray arr echo ${#arr[@]} }
Oczekuję, że to zadziała ale w momencie wyjścia z tego ostatniego { kontekstu ; } na końcu | potok tam stracisz wartość zmiennej. Dzieje się tak, ponieważ każdy z | oddzielnych | procesów w potoku | jest wykonywany w ( podpowłoka ). Więc twoja rzecz nie działa z tego samego powodu:
( arr=( a b c ) ) ; echo ${arr[@]}
… nie „t – wartość zmiennej została ustawiona w innym proces powłoki niż ten, w którym go wywołujesz.
Odpowiedź
Aby upewnić się, że readarray polecenie jest wykonywane w bieżącej powłoce, albo użyj podstawienia procesu zamiast potoku:
readarray -t arr < <( echo a; echo b; echo c )
lub (jeśli bash 4.2 lub nowsza) użyj opcji powłoki lastpipe:
shopt -s lastpipe ( echo a; echo b; echo c ) | readarray -t arr
Komentarze
Odpowiedź
readarray może również czytać ze standardowego wejścia, więc:
readarray arr <<< "$(echo a; echo b; echo c)"; echo ${#arr[@]}
< <2 strzałki?bash. Krótko mówiąc, jest to ' składnia do traktowania potoku jako deskryptora pliku.< <(...)oznacza przekierowanie danych wejściowych (pierwszego<) z danych wyjściowych polecenia wewnątrz<(...). Podobnie,> >(...)przekazałoby standardowe wyjście na standardowe wejście potoku wewnątrz>(...). Nie ' nie musisz koniecznie używać przekierowania z podstawianiem procesów.cat <( echo a b c )też działa.readarray -t arr. Odman bash:-t Remove a trailing newline from each line read.bash5.0.17 i to nie ' nie działa dla mnie. ' sprawdziłem nawetBASHOPTSi zawieralastpipe, alecat myfile.txt | readarray -t arrdaje pustearr, alereadarray -t arr < <(cat myfile.txt)działa poprawnie.