2012-10-11 21 views
7

He encontrado el comportamiento extraño para mí, que no puedo explicar. El siguiente código es un trabajo bien:valor de retorno de subshell y salida a variables locales

function prepare-archive { 
blah-blah-blah... 
_SPEC_FILE=$(check-spec-file "$_GIT_DIR/packaging/") 
exit $? 
blah-blah-blah... 
} 

significa consigo valor que espero:

bash -x ./this-script.sh: 
++ exit 1 
+ _SPEC_FILE='/home/likern/Print/Oleg/print-service/packaging/print-service.spec 
/home/likern/Print/Oleg/print-service/packaging/print-service2.spec' 
+ exit 1 

Tan pronto como agrego local definición de variables:

local _SPEC_FILE=$(check-spec-file "$_GIT_DIR/packaging/") 

I Get siguiente :

bash -x ./this-script.sh: 
++ exit 1 
+ local '_SPEC_FILE=/home/likern/Print/Oleg/print-service/packaging/print-service.spec 
/home/likern/Print/Oleg/print-service/packaging/print-service2.spec' 
+ exit 0 
$:~/MyScripts$ echo $? 
0 

Pregunta: ¿Por qué? ¿Lo que ha sucedido? ¿Puedo capturar la salida de subshell a la variable local y verificar el valor de retorno de subshell de manera confiable?

P.S.: prepare-archive se llama en el script de shell principal. La primera exit es la función exit de check-spec-file, la segunda de la función prepare-archive - esta función se ejecuta desde la secuencia de comandos principal. Devuelvo el valor de check-spec-file por exit 1, luego paso este valor a exit $?. Por lo tanto, espero que sean lo mismo.

+0

¿En qué contexto se llama 'prepare-archive'? La '++ exit 1' no encaja con ningún código que hayas mostrado. – chepner

Respuesta

4

Desde el manual de bash, Shell Builtin Commands sección:

local: 
    [...]The return status is zero unless local is used outside a function, an invalid name is supplied, or name is a readonly variable. 

Espero que esto ayude =)

+0

¿Esto significa que la definición de variable no tiene un estado de retorno cuando se usa sin 'local'? ¿Por qué? ¿Conoces algunas soluciones alternativas, ya que no quiero producir variables globales superfluas? –

+0

No conozco ninguna solución alternativa que no implique la creación de una variable global o el uso de archivos, sorry = (. Haría 'local TMPFILE = $ (mktemp); check-spec-file> $ TMPFILE ; error local = $ ?; local _SPEC_FILE = $ (cat $ TMPFILE); rm $ TMPFILE' –

+1

@Mephi_stofel - para evitarlo, puede dividir la declaración y la inicialización, por ejemplo, primero esto: 'local my_var' y eso: 'my_var = $ (my_function)'. La inicialización se referirá con seguridad a la variable local, sin contaminar el alcance global. –

12

Para capturar el código de salida de subnivel, declarar la variable como local antes de la asignación, por ejemplo, el siguiente script

#!/bin/sh 

local_test() 
{ 
    local local_var 
    local_var=$(echo "hello from subshell"; exit 1) 
    echo "subshell exited with $?" 
    echo "local_var=$local_var" 
} 

echo "before invocation local_var=$local_var in global scope" 
local_test 
echo "after invocation local_var=$local_var in global scope" 

produce la siguiente salida

before invocation local_var= in global scope 
subshell exited with 1 
local_var=hello from subshell 
after invocation local_var= in global scope 
+0

¿Me explico qué está pasando aquí? Su respuesta solucionó mi problema, pero todavía no entiendo cómo y por qué lo hace. –

+1

@IhorKaharlichenko Si se asigna una variable en la declaración con 'local', el estado de salida del subconjunto se" enmascara "/anulado por la salida s tatus del comando integrado 'local'. Declarar una variable local antes de la asignación también es más portátil (algunos shells no admiten la inicialización con 'local'). – vilpan

Cuestiones relacionadas