Bash Read: Lectura de la lista separada por comas, se pierde el último elemento

8

El resultado del comando a continuación es extraño para mí. ¿Por qué no me devuelve el elemento 5?

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

Esperaría que '5' sea devuelto también. Correr GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu). Agregar una coma funciona, pero mis datos de entrada no tienen una coma. ¿Me estoy perdiendo de algo?

Karlo
fuente

Respuestas:

12

Con read, -dse usa para terminar las líneas de entrada (es decir, no para separar las líneas de entrada). Su última "línea" no contiene ningún terminador, por lo que readdevuelve falso en EOF y el ciclo sale (aunque se haya leído el valor final).

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

(Incluso con -d, readtambién usa $IFS, absorber espacios en blanco, incluido el seguimiento \ndel valor final que aparecería usando otros métodos como readarray)

Las preguntas frecuentes de Bash discuten esto y cómo manejar varios casos similares:

Sr. púrpura
fuente
8
Supongo que uno podría hacer read -d, i || [[ -n $i ]]a la ¿Qué while read -r line || [[ -n $line ]]significa?
Steeldriver
8

Como dicen otras respuestas, -des un carácter de fin de línea, no un separador de campo. Tu puedes hacer

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

Del hombre:

-d delim

El primer carácter de delim se usa para terminar la línea de entrada, en lugar de la nueva línea.

Su elemento 5 no tiene un delimitador (coma), por lo que no se leerá.

Siva
fuente
Entonces, ¿la mejor solución es poner otra coma después de la entrada?
Karlo
3
La mejor solución podría ser procesar datos con algo que no sea un shell . Como los que respondieron aquí han abordado la pregunta actual, puede considerar una pregunta separada que demuestre su objetivo más amplio.
Jeff Schaller
3

Lo que está viendo es el mismo comportamiento (y por la misma razón) que ¿Por qué este bucle 'while' no reconoce la última línea?

Como en ese caso, puede modificar el comportamiento agregando una prueba adicional a la condición de terminación del bucle, de la siguiente manera

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
conductor de acero
fuente