2012-08-28 9 views
6

Quiero crear alias bash dentro de un bucle donde el bucle lee líneas de un comando. Para leer la salida línea por línea, creo que necesito conectar la salida al read. Cuando hago eso, sin embargo, los alias no existen.¿Por qué no puedo evaluar dentro de un ciclo while?

Si incluyo lo siguiente en mi .bashrc:

for x in a1 a2; do 
    eval "alias $x='echo foo'" 
done 

echo -e "a3\na4" | while read x; do 
    eval "alias $x='echo foo'" 
done 

Alias ​​a1 y a2 existir, pero a3 y a4 no. ¿Cuál es la diferencia entre esos dos bucles?

+0

Esto es muy común cuando se conecta a un bucle 'while'. Ver [esta respuesta] (http://stackoverflow.com/questions/7612320/bash-weird-variable-scope-when-populating-array-with-results/7612420#7612420), o [BashFAQ/024] (http: //mywiki.wooledge.org/BashFAQ/024) para detalles y varias soluciones alternativas. –

+5

Además, no hay necesidad de utilizar 'eval' aquí. 'alias $ x = 'echo foo'' expandirá' $ x' antes de definir el alias. – chepner

Respuesta

5

El problema es la tubería. En una interconexión del formulario a | b | c, cada uno de los comandos individuales a, b y c se ejecuta en una subcamada separada [ ref], lo que significa que recibe una copia del entorno de ejecución principal (incluidos alias) y cualquier cambio realiza su propia copia (como al ejecutar alias) no tendrá ningún efecto en el padre [ ref].

En su caso, se podría solucionar este problema mediante la escritura:

while read x; do 
    eval "alias $x='echo foo'" 
done < <(echo -e "a3\na4") 

que todavía se ejecutará echo -e "a3\na4" en un subnivel, pero se corre el -loop while en el ambiente normal de ejecución/padre.

+0

No he visto la sintaxis '<(command)' antes. ¿Eso es crear un descriptor de archivo apuntando a la salida de 'command'? –

+0

@JeffKlukas: Sí; se llama "sustitución de procesos" (ver http://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution) y utiliza un archivo FIFO o '/ dev/fd'. La documentación implica que no funciona en todos los sistemas, pero ha funcionado en todos los sistemas que he probado, incluido Cygwin. – ruakh

6

El ciclo while del conducto se ejecuta en una subcadena. Que puede hacer:

while read x; do 
    eval "alias $x='echo foo'" 
done << EOF 
a3 
a4 
EOF 
3

En bash 4.2 y posteriores, puede establecer la opción lastpipe para mantener la última mando de un tubo de ejecutar en un subnivel. El control de trabajos también debe estar desactivado (set +m) para que esto funcione.

shopt -s lastpipe 
set +m 
echo -e "a3\na4" | while read x; do 
    alias $x='echo foo' 
done 
+0

+1: ¡Es bueno saberlo! – ruakh

Cuestiones relacionadas