2010-11-23 25 views
9

Aquí hay un script de shell:Bash: Valor mínimo de la variable global

globvar=0 

function myfunc { 
    let globvar=globvar+1 
    echo "myfunc: $globvar" 
} 

myfunc 
echo "something" | myfunc 

echo "Global: $globvar" 

Cuando llama, se imprime el siguiente:

$ sh zzz.sh 
myfunc: 1 
myfunc: 2 
Global: 1 
$ bash zzz.sh 
myfunc: 1 
myfunc: 2 
Global: 1 
$ zsh zzz.sh 
myfunc: 1 
myfunc: 2 
Global: 2 

La pregunta es: ¿por qué sucede esto y qué comportamiento es correcto?

P. S. Tengo la extraña sensación de que la función detrás de la tubería se llama en forma de bifurcación ... Entonces, ¿puede haber una solución simple?

P.P.S. Esta función es una envoltura de prueba simple. Ejecuta la aplicación de prueba y analiza su salida. Luego incrementa las variables $ APROBADO o $ FAILADO. Finalmente, obtiene una cantidad de pruebas pasadas/fallidas en variables globales. El uso es como:

test-util << EOF | myfunc 
input for test #1 
EOF 
test-util << EOF | myfunc 
input for test #2 
EOF 
echo "Passed: $PASSED, failed: $FAILED" 

Gracias, Serge

+0

¿Ha leído: http://tldp.org/LDP/abs/html/localvar.html? –

+0

bueno, en mi opinión, $ globvar no es una variable local, porque al invocar myfunc() sin un conducto, la variable global $ globvar se incrementa bastante bien. El problema es que la función de llamada sobre la tubería no funciona en bash/sh. – zserge

Respuesta

7

Korn da los mismos resultados como zsh, por cierto.

Consulte BashFAQ/024. Las tuberías crean subcapas en Bash y las variables se pierden cuando salen las subcapas.

Basado en su ejemplo, me gustaría reestructurarlo algo como esto:

globvar=0 

function myfunc { 
    echo $(($1 + 1)) 
} 

myfunc "$globvar" 
globalvar=$(echo "something" | myfunc "$globalvar") 
+0

¡Gracias por el enlace! La pregunta es cómo devolver dos variables: $ PASSED y $ FAILED. Entiendo, que puedo buscar $ ?, si es igual a cero, incrementar $ PASADO por mi cuenta, de lo contrario, incrementar $ FAILED. Solo me gustaría tener el menor código posible fuera de myfunc(). – zserge

+0

@zserge: Una manera sería así: 'myfunc() {echo" two words "; }; lee word1 word2 <<< $ (myfunc) 'o' array = ($ (myfunc)) '. –

3

Tubería algo en myfunc en sh o bash provoca un nuevo shell para desovar. Puede confirmar esto agregando un reposo prolongado en myfunc. Mientras duerme, llama a ps y verás un subproceso. Cuando la función retorna, esa subcarpeta sale sin cambiar el valor en el proceso principal.

Si realmente necesita ese valor a ser cambiado, tendrá que devolver un valor desde la función y comprobar $ PIPESTATUS después, supongo, así:

globvar=0 

function myfunc { 
    let globvar=globvar+1 
    echo "myfunc: $globvar" 
    return $globvar 
} 

myfunc 
echo "something" | myfunc 
globvar=${PIPESTATUS[1]} 

echo "Global: $globvar" 
+0

Cool. No sabía sobre 'PIPESTATUS' antes. – dennycrane

+0

El único problema con esta técnica es que su valor de retorno debe estar en el rango 0-255. –

0

Uso export en lugar de let, de lo contrario la variable es local (uso $ (()), así que hacer una operación aritmética)

export globvar=0 

function myfunc { 
    export globvar=$((globvar+1)) 
    echo "myfunc: $globvar" 
} 
+0

pero las variables exportadas no regresan al intérprete de llamadas, por lo que si llamas a tu función por tubería, tu variable global permanecerá sin cambios (probada en bash) – zserge

+0

mi error, no vi el | problema. ¿Por qué necesita llamar a un nuevo shell en lugar de simplemente llamar al script? – mb14

+0

En realidad, yo no. Solo necesito redireccionar una salida del programa de prueba a la función de shell para averiguar si la prueba fue exitosa. Una forma clara de redirigir la salida es un conducto, pero el tubo forma un subconjunto. – zserge

0

El problema es '¿qué extremo de una tubería que utiliza complementos se ejecuta mediante el proceso original?'

En zsh, parece que el último comando en la tubería es ejecutado por el script de shell principal cuando el comando es una función o está incorporado.

En Bash (y sh es probable que sea un enlace a Bash si está en Linux), ambos comandos se ejecutan en un subconjunto o el primer comando se ejecuta mediante el proceso principal y los otros son dirigido por subcapas.

Claramente, cuando la función se ejecuta en un subconjunto, no afecta a la variable en el shell principal (solo el global en el subconjunto).

considerar la adición de una prueba adicional:

echo Something | { myfunc; echo $globvar; } 
echo $globvar 
Cuestiones relacionadas