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.
bash
5.0.17 i to nie ' nie działa dla mnie. ' sprawdziłem nawetBASHOPTS
i zawieralastpipe
, alecat myfile.txt | readarray -t arr
daje pustearr
, alereadarray -t arr < <(cat myfile.txt)
działa poprawnie.