Problem readarray (lub pipe)

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

  • Super. To działa, ale czym dokładnie jest podstawianie procesu? A co to znaczy mieć < < 2 strzałki?
  • Zobacz stronę podręcznika 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.
  • Obie te opcje dają mi niepożądany wynik, w którym każdy element tablicy zachowuje końce linii na końcu każdego ciągu. Podczas gdy odpowiedź smac89 nie ma tego problemu.
  • Zakończenia linii można usunąć za pomocą readarray -t arr. Od man bash: -t Remove a trailing newline from each line read.
  • I ' m używając bash 5.0.17 i to nie ' nie działa dla mnie. ' sprawdziłem nawet BASHOPTS i zawiera lastpipe, ale cat myfile.txt | readarray -t arr daje puste arr, ale readarray -t arr < <(cat myfile.txt) działa poprawnie.

Odpowiedź

readarray może również czytać ze standardowego wejścia, więc:

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

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *