Usando "while read ..." en un script de Linux

34

¿Podría alguien explicar cómo funciona el siguiente código?

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

Específicamente, me gustaría saber por qué la salida de este bucle es 3 4 5 6 2 1, en lugar de 3 2 1y 6 5 4en dos líneas separadas. Parece que no puedo entenderlo ...

linuxgringo
fuente

Respuestas:

41

readlee una línea completa desde la entrada estándar, divide la línea en campos y asigna estos campos a las variables dadas. Si hay más piezas que variables, las piezas restantes se asignan a la última variable.

En su caso $ase le asigna 1, $bse le asigna 2y $cel resto 3 4 5 6.

Florian Diesch
fuente
Gracias Florian! Ahora tiene sentido ... Por alguna razón, pensé que los espacios delimitarían cada lectura variable, pero aparentemente no. ¡¡Aprecio tu ayuda!!
linuxgringo
24

Reescribir el ciclo de esta manera revela lo que está sucediendo:

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

Esto da, como su salida:

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

Observe primero que solo se ejecuta un comando echo. Si se ejecutara más de una vez, vería, entre otras cosas, las subcadenas (iteration beginning)e (iteration ending)impresas más de una vez.

Esto quiere decir que tener un whilebucle aquí no es realmente lograr nada. El readarchivo incorporado lee el texto separado por espacios en blanco 1 en cada variable especificada. La entrada adicional se agrega al final de la última variable especificada. 2 Así, las variables ay btoman los valores 1y 2respectivamente, mientras que ctoman el valor 3 4 5 6.

Cuando la condición del bucle ( while read a b c) se evalúa por segunda vez, no hay más entradas disponibles desde la tubería (solo lo canalizamos una sola línea de texto), por lo que el readcomando se evalúa como falso en lugar de verdadero y el bucle se detiene (antes de ejecutar el cuerpo por segunda vez).

1 : Para ser técnico y específico, el readincorporado , cuando pasa los nombres de las variables como argumentos, lee la entrada, dividiéndola en "palabras" separadas cuando encuentra espacios en blanco IFS (vea también esta pregunta y este artículo ).

2 : readel comportamiento de bloquear cualquier campo adicional de entrada en la última variable especificada no es intuitivo para muchos scripters, al principio. Se vuelve más fácil de entender cuando se considera que, como dice la respuesta de Florian Diesch , readsiempre (intentará) leer una línea completa, y que readestá destinada a ser utilizable con y sin bucle.

Eliah Kagan
fuente
Eliah, gracias por tomarte el tiempo de explicar todos los detalles. Sospeché que eso whileno cumplía su propósito normal en este ejemplo, pero luego el readcomando me arrojó ... De alguna manera, lo interpreté como "mientras read a b cno sea falso, hazlo echo ...". Gracias por explicar cómo funcionó realmente. Me encontré con este código ayer y sabía que me molestaría hasta que lo descubriera ... jajaja
linuxgringo
@linuxgringo En realidad, el cuerpo del bucle se ejecuta cada vez que se read a b cevalúa como verdadero, y la condición del bucle ( read a b c) se ejecuta más de una vez. Bit solo se evalúa como verdadero la primera vez. La segunda vez, no hay más entradas para leer desde la tubería, por lo que se encuentra el final del archivo , lo readque hace que se devuelva falso . (Consulte la última sección de la salida de help read, en "Estado de salida", para obtener detalles, y observe que, en las secuencias de comandos de shell, cero significa verdadero y no cero significa falso). Si conecta más de una línea de entrada while read ..., el cuerpo del bucle ser ejecutado varias veces.
Eliah Kagan