Use el command builtin de lectura de bash sin un bucle while

Estoy acostumbrado a la function de read integrada de bash en ciclos while, por ejemplo:

 echo "0 1 1 1 1 2 2 3" |\ while read AB; do echo $A + $B | bc; done 

He estado trabajando en algún proyecto make , y se hizo prudente dividir files y almacenar resultados intermedios. Como consecuencia, a menudo termino triturando líneas simples en variables. Si bien el siguiente ejemplo funciona bastante bien,

 head -n1 somefile | while read ABCDE FOO; do [... use vars here ...]; done 

es algo estúpido, porque el ciclo while nunca se ejecutará más de una vez. Pero sin el while ,

 head -n1 somefile | read ABCDE FOO; [... use vars here ...] 

Las variables de lectura están siempre vacías cuando las uso. Nunca me di count de este comportamiento de read , porque generalmente usaría ciclos while para procesar muchas líneas similares. ¿Cómo puedo usar la bash de read bash sin un ciclo while? ¿O hay otra (o mejor) forma de leer una sola línea en múltiples (!) Variables?

Conclusión

Las respuestas nos enseñan, es un problema de scope. La statement

  cmd0; cmd1; cmd2 | cmd3; cmd4 

se interpreta de forma tal que los commands cmd0 , cmd1 y cmd4 se ejecuten en el mismo ámbito, mientras que a los commands cmd2 y cmd3 les asigna su propia subshell y, en consecuencia, diferentes ámbitos. El shell original es el padre de ambas subcapas.

Es porque la parte donde usas los vars es un nuevo set de commands. Use esto en su lugar:

 head somefile | { read ABCDE FOO; echo $A $B $C $D $E $FOO; } 

Tenga en count que, en esta syntax, debe haber un espacio después de { y a ; (punto y coma) antes de } También -n1 no es necesario; read solo lee la primera línea.

Para una mejor comprensión, esto puede ayudarte; hace lo mismo que arriba:

 read ABCDE FOO < <(head somefile); echo $A $B $C $D $E $FOO 

Editar:

A menudo se dice que las siguientes dos declaraciones hacen lo mismo:

 head somefile | read ABCDE FOO read ABCDE FOO < <(head somefile) 

Bueno no exactamente. El primero es una tubería desde la head a la read bash . Un stdout de process a stdin de otro process.

La segunda statement es la networkingirección y la sustitución del process. Es manejado por bash mismo. Crea un FIFO (named pipe, <(...) ) al que se conecta la salida del head , y lo networkingirige ( < ) al process de read .

Hasta ahora, estos parecen equivalentes. Pero cuando se trabaja con variables, puede importar. En el primero, las variables no se establecen después de la ejecución. En el segundo, están disponibles en el entorno actual.

Cada caparazón tiene otro comportamiento en esta situación. Ver ese enlace para el que están. En bash , puede solucionar ese comportamiento con la agrupación de commands {} , la sustitución de processs ( < <() ) o Here strings ( <<< ).

Para citar de un artículo muy útil wiki.bash-hackers.org :

Esto se debe a que los commands del conducto se ejecutan en subcapas que no pueden modificar el shell primario. Como resultado, las variables del shell primario no se modifican (vea el artículo: Bash y el tree de processs ).

Como la respuesta se ha proporcionado algunas veces, una forma alternativa (usar commands no integrados …) es esta:

 $ eval `echo 0 1 | awk '{print "A="$1";B="$2}'`;echo $B $A $ 1 0 

Como notó, el problema fue que una tubería para read se ejecuta en una subcapa.

Una respuesta es usar un henetworkingoc :

 numbers="01 02" read first second <<INPUT $numbers INPUT echo $first echo $second 

Este método es bueno porque se comportará de la misma manera en cualquier shell de tipo POSIX.