Lettura bash: lettura dell'elenco separato da virgole, ultimo elemento mancante


8

L'output del comando seguente è strano per me. Perché non mi restituisce l'elemento 5?

$ echo '0,1,2,3,4,5' | while read -d, i; do echo $i; done
0
1
2
3
4

Mi aspetto che anche '5' venga restituito. In esecuzione GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu). L'aggiunta di una virgola funziona, ma i miei dati di input non hanno una virgola. Mi sto perdendo qualcosa?

Risposte:


12

Con read, -dviene utilizzato per terminare le linee di ingresso (cioè non per separare le linee di ingresso). L'ultima "riga" non contiene alcun terminatore, quindi readrestituisce false su EOF e il ciclo termina (anche se è stato letto il valore finale).

echo '0,1,2,3,4,5' | { while read -d, i; do echo "$i"; done; echo "last value=$i"; }

(Anche con -d, readutilizza anche $IFS, assorbendo spazi bianchi incluso il trascinamento \nsul valore finale che apparirebbe usando altri metodi come readarray)

Le FAQ di Bash ne discutono e come gestire vari casi simili:


8
Immagino che uno potrebbe fare read -d, i || [[ -n $i ]]alla la Cosa while read -r line || [[ -n $line ]]significa?
Steeldriver,

8

Come affermano altre risposte, -dè un carattere di fine riga, non un separatore di campo. Tu puoi fare

IFS=, read -a fields <<< "1,2,3,4,5"
for i in "${fields[@]}"; do echo "$i"; done

5

Dall'uomo:

-d delim

Il primo carattere di delim viene utilizzato per terminare la riga di input, piuttosto che newline.

Il tuo elemento 5 non ha un delimitatore (virgola), quindi non verrà letto.


Quindi la soluzione migliore è inserire un'altra virgola dopo l'input?
Karlo,

3
La soluzione migliore potrebbe essere quella di elaborare i dati con qualcosa di diverso da una shell . Poiché i rispondenti qui hanno affrontato la domanda attuale, potresti considerare una domanda separata che dimostra il tuo obiettivo più ampio.
Jeff Schaller

3

Quello che vedi è lo stesso comportamento (e per lo stesso motivo) di Perché questo ciclo 'while' non riconosce l'ultima riga?

Come in quel caso, è possibile modificare il comportamento aggiungendo un test aggiuntivo alla condizione di terminazione del loop, come segue

while read -d, i || [[ -n $i ]]; do ...

Ex.

$ echo '0,1,2,3,4,5' | while read -d, i || [[ -n $i ]]; do echo $i; done
0
1
2
3
4
5
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.