2011-10-04 11 views
9

Necesito leer algunos datos de configuración en variables de entorno en un script bash.bash coproc y salida coproc sobrante

El patrón "obvio" (pero incorrecta) es:

egrep "pattern" config-file.cfg | read VAR1 VAR2 VAR3 etc... 

Esta falla porque el read está dirigido de una subcapa y por lo tanto no puede establecer variables en la cáscara que invoque. Así que se me ocurrió esto como una alternativa

coproc egrep "pattern" config-file.cfg 
read -u ${COPROC[0]} VAR1 VAR2 VAR3 etc... 

que funciona bien.

Para probar qué sucede si el coproceso vuelve más de una línea, he intentado esto:

coproc cat config-file.cfg 
read -u ${COPROC[0]} VAR1 VAR2 VAR3 etc... 

donde config-file.cfg contiene tres líneas.

$ cat config-file.cfg 
LINE1 A1 B1 C1 
LINE2 A2 B2 C2 
LINE3 A3 B3 C3 

Esperaba que esto procesara la primera línea del archivo, seguido de algún tipo de mensaje de error de "tubería rota". Si bien hizo procesar la primera línea, no hubo ningún mensaje de error y no se dejó ningún proceso en curso.

Así que luego trató lo siguiente en una secuencia de comandos:

$ cat test.sh 
coproc cat config-file.cfg 
read -u ${COPROC[0]} VAR1 VAR2 VAR3 VAR4 
echo $VAR1 $VAR2 $VAR3 $VAR4 
wait 
echo $? 

Ejecutarlo:

$ bash -x test.sh 
+ read -u 63 VAR1 VAR2 VAR3 VAR4 
+ cat config-file.cfg 
LINE1 A1 B1 C1 
+ wait 
+ echo 0 
0 

¿Dónde han ido las dos líneas restantes? Hubiera esperado que se colgara el "tubo roto" o el wait, ya que no había nada para leer las líneas restantes, pero como pueden ver, el código de retorno era cero.

+3

A menos que me falta algo, algo como 'leer VAR1 VAR2 VAR3 <<(egrep" patrón "config-file.cfg)" sería suficiente, ¿no? –

+0

@ShawnChin: eso está ignorando la pregunta. Los Coprocs son geniales por buenas razones para que el OP no tenga que explicar primero – sehe

+1

Disculpe mi ignorancia. Admito que los coprocs son geniales, pero el comentario fue una respuesta a una idea pasajera de que coprocs podría ser una exageración si es simplemente para evitar 'leer ejecutarse en una subcadena y perder los vars. Probablemente estoy equivocado, como de costumbre. –

Respuesta

5

Según los comentarios anteriores, puede usar process substitution para lograr eso. De esta forma, read no se ejecuta en una subshell y los vars capturados estarán disponibles dentro del shell actual.

read VAR1 VAR2 VAR3 < <(egrep "pattern" config-file.cfg) 

"Si se utiliza la forma < (lista), el fichero pasado como argumento debe ser leído para obtener la salida de la lista" - lo que significa "fichero pasado como agrument" son ellos hablando?

Eso es bastante críptico para mí también.El chapter on process substitution en Advanced Bash-scripting Guide tiene una explicación más completa.

De la forma en que lo veo, cuando se usa la sintaxis <(cmd), la salida cmd se pone a disposición mediante un conducto con nombre (o archivo temporal) y la sintaxis se reemplaza por el nombre de archivo del conducto/archivo. Así que para el ejemplo anterior, sería llegar a ser equivalente a:

read VAR1 VAR2 VAR3 < /dev/fd/63 

donde /dev/fd/63 es la canalización con nombre conectado a la salida estándar de cmd.

+0

Perfecto, gracias! Seguí el enlace que me proporcionó, y ahora está en mi colección permanente de referencia bash :-) –

+0

Me alegro de poder ayudar :) –

2

si he entendido bien su pregunta (y espero que no estoy afirmando lo obvio), leer lee una línea a la vez, como en:

$ read a b c < config-file.cfg && echo $? 
0 

o:

$ printf '%s\n%s\n' one two | { read; echo "$REPLY";} 
one 

$ echo ${PIPESTATUS[@]} 
0 0 

Para leer toda la entrada que necesita un bucle:

$ coproc cat config-file.cfg 
[1] 3460 

$ while read -u ${COPROC[0]} VAR1 VAR2 VAR3; do echo $VAR1 $VAR2 $VAR3; done 
LINE1 A1 B1 C1 
LINE2 A2 B2 C2 
LINE3 A3 B3 C3 
[1]+ Done     coproc COPROC cat config-file.cfg 

Solo para agregar que esto se explica en el FAQ.

+1

No, entiendo que 'leer' se lee una línea a la vez. Lo que me preguntaba fue qué pasó con las líneas amortiguadas cuando lees solo una de ellas. Esperaba un error o un bloqueo, pero simplemente desaparecieron, que en realidad es lo que quiero, pero odio "magia" que no entiendo y que no puedo predecir. –

+0

El co-proc simplemente no espera a que usted lea su entrada (como un tubo normal), agota el tiempo de espera. Considere lo siguiente: '$ {echo 1; echo 2;} 2' y '$ {echo 1; echo 2;} | {leer; echo $ RESPUESTA; } 1'. ¿A dónde fue 2? –

+0

Entonces, para reformular la respuesta: en este caso, el co-proceso se cierra cuando ve un final de archivo en su entrada. Bart Shaefer escribió un tutorial muy bueno sobre coprocesos, puede encontrarlo [aquí] (http://www.zsh.org/mla/users/2011/msg00095.html). –

Cuestiones relacionadas