En el siguiente programa, si configuro la variable $fooen el valor 1 dentro de la primera ifinstrucción, funciona en el sentido de que su valor se recuerda después de la instrucción if. Sin embargo, cuando configuro la misma variable en el valor 2 dentro de un ifque está dentro de una whiledeclaración, se olvida después del whileciclo. Se comporta como si estuviera usando algún tipo de copia de la variable $foodentro del whilebucle y estoy modificando solo esa copia en particular. Aquí hay un programa de prueba completo:
#!/bin/bash
set -e
set -u
foo=0
bar="hello"
if [[ "$bar" == "hello" ]]
then
foo=1
echo "Setting \$foo to 1: $foo"
fi
echo "Variable \$foo after if statement: $foo"
lines="first line\nsecond line\nthird line"
echo -e $lines | while read line
do
if [[ "$line" == "second line" ]]
then
foo=2
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo "Value of \$foo in while loop body: $foo"
done
echo "Variable \$foo after while loop: $foo"
# Output:
# $ ./testbash.sh
# Setting $foo to 1: 1
# Variable $foo after if statement: 1
# Value of $foo in while loop body: 1
# Variable $foo updated to 2 inside if inside while loop
# Value of $foo in while loop body: 2
# Value of $foo in while loop body: 2
# Variable $foo after while loop: 1
# bash --version
# GNU bash, version 4.1.10(4)-release (i686-pc-cygwin)
bash
while-loop
scope
sh
Eric Lilja
fuente
fuente

SC2030: Modification of foo is local (to subshell caused by pipeline).Respuestas:
los
whilebucle se ejecuta en una subshell. Por lo tanto, los cambios que realice en la variable no estarán disponibles una vez que la subshell salga.En su lugar, puede usar una cadena here para volver a escribir el ciclo while para estar en el proceso de shell principal; solo
echo -e $linesse ejecutará en una subshell:Puede deshacerse de lo bastante feo
echoen la cadena de aquí arriba expandiendo las secuencias de barra invertida inmediatamente al asignarlines. La$'...'forma de cita se puede usar allí:fuente
<<< "$(echo -e "$lines")"a simple<<< "$lines"tail -flugar de texto fijo?while read -r line; do echo "LINE: $line"; done < <(tail -f file)(obviamente, el bucle no terminará ya que continúa esperando la entrada detail).whilebucle o elforbucle; más bien el uso de subshell, es decir, incmd1 | cmd2,cmd2está en un subshell. Entonces, siforse ejecuta un bucle en una subshell, se mostrará el comportamiento inesperado / problemático.ACTUALIZADO # 2
La explicación está en la respuesta de Blue Moons.
Soluciones alternativas:
Eliminar
echoAgregue el eco dentro del documento aquí-es-el-documento
Ejecutar
echoen segundo plano:Redireccionar a un identificador de archivo explícitamente (¡Cuidado con el espacio
< <!):O simplemente redirigir a
stdin:Y uno para
chepner(eliminarecho):La variable
$linesse puede convertir en una matriz sin iniciar un nuevo sub-shell. Los caracteres\ynse deben convertir a algún carácter (por ejemplo, un carácter de línea real nuevo) y utilizar la variable IFS (Separador de campo interno) para dividir la cadena en elementos de la matriz. Esto se puede hacer como:El resultado es
fuente
linesúnico propósito de la variable parece ser alimentar elwhileciclo.for line in $(echo -e $lines); do ... doneUsted es el 742342º usuario que hace estas preguntas frecuentes sobre bash. La respuesta también describe el caso general de las variables establecidas en subcapas creadas por tuberías:
fuente
Hmmm ... casi juraría que esto funcionó para el shell Bourne original, pero no tengo acceso a una copia en ejecución ahora para verificar.
Sin embargo, hay una solución muy trivial al problema.
Cambie la primera línea del guión de:
a
Et voila! Una lectura al final de una tubería funciona bien, suponiendo que tenga instalado el shell Korn.
fuente
Utilizo stderr para almacenar dentro de un bucle, y leo desde afuera. Aquí var i se establece inicialmente y se lee dentro del bucle como 1.
O utilice el método heredoc para reducir la cantidad de código en una subshell. Tenga en cuenta que el valor iterativo i se puede leer fuera del ciclo while.
fuente
¿Qué tal un método muy simple
fuente
Esta es una pregunta interesante y toca un concepto muy básico en Bourne shell y subshell. Aquí proporciono una solución que es diferente de las soluciones anteriores haciendo algún tipo de filtrado. Daré un ejemplo que puede ser útil en la vida real. Este es un fragmento para verificar que los archivos descargados se ajustan a una suma de verificación conocida. El archivo de suma de comprobación tiene el siguiente aspecto (mostrando solo 3 líneas):
El script de shell:
El padre y el subshell se comunican a través del comando echo. Puede elegir un texto fácil de analizar para el shell principal. Este método no rompe su forma normal de pensar, solo que tiene que hacer un procesamiento posterior. Puede usar grep, sed, awk y más para hacerlo.
fuente