2012-10-11 7 views
7

Ho trovato lo strano comportamento per me, che non riesco a spiegare. Il seguente codice è un lavoro OK:valore di ritorno da subshell e output a variabili locali

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

significa ottengo valore che mi aspetto:

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 

Non appena aggiungo local definizione di variabile:

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

ottengo seguente :

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 

Domanda: Perché? Cos'è successo? Posso rilevare l'output dalla subshell alla variabile local e controllare il valore di ritorno della sottoscocca in modo affidabile?

P.S.: prepare-archive viene chiamato nello script della shell principale. Il primo exit è il dalla funzione check-spec-file, il secondo dalla funzione prepare-archive - questa funzione viene eseguita dallo script della shell principale. Rendo il valore da check-spec-file per exit 1, quindi passa questo valore a exit $?. Quindi mi aspetto che dovrebbero essere uguali.

+0

In quale contesto viene chiamato 'prepare-archive'? '++ exit 1' non si adatta a nessun codice che hai mostrato. – chepner

risposta

4

Dal manuale bash, Shell Builtin Commands sezione:

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

Spero che questo aiuti =)

+0

Ciò significa che la definizione della variabile non ha lo stato di ritorno quando viene usata senza 'local'? Perché? Conosci qualche soluzione alternativa, perché non voglio produrre variabili globali superflue. –

+0

Non sono a conoscenza di soluzioni alternative che non implichino la creazione di una variabile globale o l'uso di file, sorry = (. Vorrei fare 'local TMPFILE = $ (mktemp); check-spec-file> $ TMPFILE ; errore locale = $ ?; locale _SPEC_FILE = $ (cat $ TMPFILE); rm $ TMPFILE' –

+1

@Mephi_stofel - per aggirare il problema, è possibile dividere la dichiarazione e l'inizializzazione, ad esempio prima questo: 'local my_var' e quindi: 'my_var = $ (my_function)'. L'inizializzazione farà sicuro riferimento alla variabile locale, senza inquinare l'ambito globale –

12

in condizione di ripresa l'uscita di subshell, dichiarare la variabile come locali prima della cessione, ad esempio, il seguente 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 il seguente output

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

mente spiegando cosa sta succedendo qui? La tua risposta ha risolto il mio problema, ma ancora non capisco come e perché lo fa. –

+1

@IhorKaharlichenko Se una variabile è assegnata alla dichiarazione con 'local', lo stato di uscita della sub-shell è" mascherato "/sovrascritto dall'uscita s tato del comando integrato 'local'. Dichiarare una variabile locale prima dell'assegnazione è anche più portabile (alcune shell non supportano l'inizializzazione con 'local'). – vilpan