2016-06-19 11 views
2

Dieses Beispiel auf Mac El Capitan mit bash getestet wurdebash Befehl Substitution externe Skriptfunktion empfängt falschen Exit-Status

main_script.sh:

HINWEIS: func_a und func_b identisch sind mit Ausnahme der Linie, Die lokale Variable output ist deklariert.

func_a() { 
    local output 
    output="$(./external.sh some_function)" 
    if [ $? -eq 0 ];then 
     echo "A zero result ($?) -> $output <- end" 
    else 
     echo "A other result ($?) -> $output <- end" 
    fi 
} 

func_b() { 
    local output="$(./external.sh some_function)" 
    if [ $? -eq 0 ];then 
     echo "B zero result ($?) -> $output <- end" 
    else 
     echo "B other result ($?) -> $output <- end" 
    fi 
} 

func_a 
func_b 

external.sh:

some_function() { 
    echo "this is the output" 
    return 1 
} 

"[email protected]" 

Wenn ich laufen main_script die Ausgabe lautet:

würde
A other result (1) -> this is the output <- end 
B zero result (0) -> this is the output <- end 

Aus welchem ​​Grund die Deklaration einer lokalen Variablen auf der gleichen Linie wie die Befehlserteilung beeinflusst die Ergebnisse? Könnte das ein Fehler sein oder fehle ich etwas?

+0

Dies könnte helfen: [Wie ein Bash-Skript zu debuggen?] (Http://unix.stackexchange.com/q/155551/74329) – Cyrus

+0

Gut bewusst, wie ein Bash-Skript zu debuggen und was Set -x tut. Ich habe einfach versucht, die Ausgabe so klar wie möglich zu machen. Ich weiß, was das Problem ist, jetzt frage ich mich warum. Scheint, eine lokale Var zu deklarieren, gibt null zurück, egal was. Scheint wie ein Bash Bug? – arctelix

Antwort

2

Der Grund dafür ist, dass $? in func_b den Erfolg der eher gebautet local reflektiert als der Erfolg der Befehl Substitution ($(...)).

Der local builtin gelingt es, wenn die Zuordnung syntaktisch korrekt ist - unabhängig davon, ob irgendein Befehl Substitution an der RHS ausfällt oder nicht.

Beachten Sie, dass dies analog für die declare und export Builtins gilt.

mit einem einfachen Beispiel zu veranschaulichen:

declare output="$(false)"; echo $? # -> 0(!) - even though `false` obviously fails. 

Dagegen ist wenn keine builtin beteiligt - im Fall eine einfachen variable Zuordnung - eine Versagen Befehl Substitution in reflektiertem $?:

output="$(false)"; echo $? # -> 1(!) - simple assignment; $(...) exit code is reported 

Dieser unlogisch Unterschied im Verhalten wird durch die Tatsache erklärt, dass local/declare/export sind builtins eher als Teil der Shell-Syntax.

Als builtins (integrierten Befehle), werden sie wie Befehle behandelt, und Befehle werden erwartet, um ihren Erfolg/Misserfolg über ihren eigenen Exit-Code zu signalisieren; im Fall der Builtins, wie gesagt, wird eine syntaktisch korrekte Zuweisung als Erfolg betrachtet - mit anderen Worten: wenn etwas zugewiesen werden könnte - selbst wenn das etwas die Nullzeichenfolge aufgrund einer fehlgeschlagenen Befehlsersetzung auf der RHS ist - der eingebaute gelungen.

+0

Das war, was ich dachte, ging los. Irgendwie albern, dass das Erklären einer Variablen den Erfolg des Auftrags ersetzen würde. Aber dann wieder sind die Dinge in Shell-Shell-Land selten intuitiv. – arctelix

+0

@arctelix: Es ist definitiv kontraintuitiv; Ich habe einige Hintergrundinformationen hinzugefügt, die hoffentlich zumindest erklären, warum es passiert. – mklement0