Utilizzo di "while read ..." in uno script linux


34

Qualcuno potrebbe spiegare come funziona il seguente codice?

echo '1 2 3 4 5 6' | while read a b c
do
  echo $c $b $a
done

In particolare, vorrei sapere perché l'output di questo loop è 3 4 5 6 2 1, anziché 3 2 1e 6 5 4su due righe separate? Non riesco a pensarci bene ...

Risposte:


41

readlegge un'intera riga dall'input standard, divide la riga in campi e assegna questi campi alle variabili indicate. Se ci sono più pezzi che variabili, i pezzi rimanenti vengono assegnati all'ultima variabile.

Nel tuo caso $aviene assegnato 1, $bviene assegnato 2e $cil resto 3 4 5 6.


Grazie Florian! Ora ha senso ... Per qualche ragione ho pensato che gli spazi avrebbero delimitato ogni lettura variabile, ma apparentemente no. Apprezzo il vostro aiuto!!
linuxgringo

24

Riscrivere il loop in questo modo rivela ciò che sta accadendo:

echo '1 2 3 4 5 6' | while read a b c
  do
    echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
  done

Questo da come output:

(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)

Si noti innanzitutto che viene eseguito solo un singolo comando echo. Se fosse eseguito più di una volta, vedresti, tra le altre cose, vedere le sottostringhe (iteration beginning)e (iteration ending)stampate più di una volta.

Questo per dire che avere un whileciclo qui non sta realizzando nulla. L' readintegrato legge il testo 1 separato da spazi bianchi in ciascuna variabile specificata. L'input extra viene aggiunto alla fine dell'ultima variabile specificata. 2 Quindi variabili ae bassumono i valori 1e 2rispettivamente, mentre cassumono il valore 3 4 5 6.

Quando la condizione del ciclo ( while read a b c) viene valutata per la seconda volta, non è più disponibile alcun input dal pipe (abbiamo eseguito il piping di una sola riga di testo), quindi il readcomando restituisce false invece che true e il ciclo si interrompe (prima di eseguire corpo una seconda volta).

1 : Per essere tecnico e specifico, l' readintegrato , quando passa nomi di variabili come argomenti, legge l'input, suddividendolo in "parole" separate quando incontra spazi bianchi IFS (vedi anche questa domanda e questo articolo ).

2 : readIl comportamento di inceppare eventuali campi extra di input nell'ultima variabile specificata non è inizialmente intuitivo per molti scripter. Diventa più facile da capire se si considera che, come dice la risposta di Florian Diesch , readsarà sempre (tentato di) leggere un'intera riga - e che readsi intende sia utilizzabile con e senza un ciclo.


Elia, grazie per aver dedicato del tempo a spiegare tutti i dettagli. Sospettavo che whilein questo esempio non servisse al suo scopo normale, ma poi il readcomando mi ha respinto ... In qualche modo, l'ho interpretato come "mentre read a b cnon è falso, fallo echo ...". Grazie per aver spiegato come ha funzionato davvero. Ho trovato questo codice ieri e sapevo che mi avrebbe
disturbato

@linuxgringo In realtà, il corpo del ciclo viene eseguito ogni volta che viene read a b cvalutato come vero e la condizione del ciclo ( read a b c) viene eseguita più di una volta. Bit valuta solo su true la prima volta. La seconda volta, non c'è più input da leggere dalla pipe, quindi viene rilevata la fine del file , che readrestituisce false . (Vedi l'ultima sezione dell'output di help read, su "Exit Status", per i dettagli, osservando che, nello scripting della shell, zero significa vero e diverso da zero significa falso.) Se eseguissi il piping di più di una riga di input while read ..., il corpo del loop verrebbe essere eseguito più volte.
Eliah Kagan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.