2012-10-11 17 views
7

Ich habe das seltsame Verhalten für mich gefunden, was ich nicht erklären kann. Der folgende Code ist Arbeit OK:Rückgabewert von Subshell und Ausgabe an lokale Variablen

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

bedeutet, dass ich Wert bekommen, den ich erwarten:

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 

Sobald ich local Definition Variable hinzufügen:

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

ich folgende erhalten :

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 

Frage: Warum? Was ist passiert? Kann ich die Ausgabe von der Subshell auf die Variable local abfangen und den Rückgabewert der Subshell zuverlässig überprüfen?

P.S.: prepare-archive wird im Shell-Hauptskript aufgerufen. Die erste 10 ist die 10 von check-spec-file Funktion, die zweite von prepare-archive Funktion - diese Funktion selbst wird von Haupt-Shell-Skript ausgeführt. Ich gebe einen Wert von check-spec-file durch exit 1 zurück und übergebe diesen Wert an exit $?. Also erwarte ich, dass sie gleich sein sollten.

+0

In welchem ​​Kontext wird 'prepare-archive' aufgerufen? Der '++ exit 1' passt nicht zu dem Code, den Sie angezeigt haben. – chepner

Antwort

4

Von der bash Handbuch Shell Builtin Commands Abschnitt:

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

hoffe, das hilft =)

+0

Bedeutet dies, dass die Variablendefinition keinen Rückgabewert hat, wenn sie ohne 'local' verwendet wird? Warum? Kennen Sie einige Workarounds - da ich keine überflüssigen globalen Variablen erzeugen möchte. –

+0

Mir sind keine Problemumgehungen bekannt, die nicht die Erstellung einer globalen Variablen oder die Verwendung von Dateien beinhalten, sorry = (. Ich würde 'local TMPFILE = $ (mktemp); check-spec-file> $ TMPFILE ; lokaler Fehler = $ ?; local _SPEC_FILE = $ (cat $ TMPFILE); rm $ TMPFILE' –

+1

@Mephi_stofel - um es zu umgehen, können Sie die Deklaration und Initialisierung teilen, zB zuerst das: 'local my_var' und dann: 'my_var = $ (my_function)'. Die Initialisierung wird sicher auf die lokale Variable verweisen, ohne den globalen Bereich zu verschmutzen. –

12

Um Subshell des Exit-Status zu erfassen, erklären die Variable als lokale vor der Zuweisung zum Beispiel das folgende Skript

#!/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" 

die folgende Ausgabe erzeugt

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

Würdest du Verstand, was hier passiert? Ihre Antwort behebt mein Problem, aber ich verstehe immer noch nicht, wie und warum es das tut. –

+1

@IhorKaharlichenko Wenn eine Variable bei der Deklaration mit 'local' zugewiesen wird, ist der Subshell-Exit-Status" maskiert "/durch den Ausgang s überschrieben tatus des eingebauten Befehls 'local'. Das Deklarieren einer lokalen Variablen vor der Zuweisung ist auch portabler (einige Shells unterstützen keine Initialisierung mit 'local'). – vilpan