2014-05-22 7 views
5

Ich spielte mit trap innerhalb einer Funktion wegen this question rum und kam mit dieser sekundären Frage. Angesichts den folgenden Code:Wohin geht der Exit-Status nach Trap/Return?

d() { 
    trap 'return' ERR 
    false 
    echo hi 
} 

Wenn ich d laufen, die trap bewirkt, dass der Schal aus der Funktion zurück, ohne Druck ‚hallo‘. So weit, ist es gut. Aber wenn ich es ein zweites Mal ausführen, erhalte ich eine Nachricht aus der Schale:

-bash: Rückkehr: kann nur `return‘ aus einer Funktion oder sourced Skript

Zuerst nahm ich Das bedeutete, dass das ERR-Signal zweimal vorkam: Einmal, wenn false einen Nicht-Null-Exit-Status (innerhalb der Funktion) gab und erneut, wenn die Funktion selbst mit einem Nicht-Null-Exit-Status (außerhalb der Funktion) zurückkehrte. Aber diese Hypothese nicht halten gegen diesen Test up:

e() { 
    trap 'echo +;return' ERR 
    false 
    echo hi 
} 

Wenn ich laufen die oben, egal wie oft ich es laufen, ich nicht mehr bekommen die kann nur return aus einer Funktion oder sourced Skript Warnung von bash. Warum behandelt die Shell einen zusammengesetzten Befehl, der sich von einem einfachen Befehl in einem trap arg unterscheidet?

Mein Ziel war es, den tatsächlichen Exit-Status des Befehls zu erhalten, dass die Funktion verursacht zu verlassen, aber ich denke, was das obige Verhalten verursacht macht auch den Exit-Status Erfassung kompliziert:

f() { 
    trap ' 
     local s=$? 
     echo $s 
     return $s' ERR 
    false 
    echo hi 
} 

bash> f; echo $? 
1 
0 

Wat? Kann jemand bitte erklären, warum sich hier auf zwei verschiedene Werte ausdehnt und, wenn es sich herausstellt, dass es die gleiche Ursache ist, die obige Unterscheidung zwischen return und echo +; return?

+1

Es gibt einige überraschende Umfangsprobleme hier. Ihre Traps sind nicht funktionsspezifisch, sondern global. Beachten Sie, dass, wenn Sie Ihre e() - Funktion erstellen und dann einen ungültigen Befehl eingeben, z. B. "ggg", Ihre Trap trifft und Sie die Fehlermeldung erhalten. Tracing mit -vx zeigt auch, dass Sie in Ihrem ersten Beispiel zweimal "zurückkehren", nachdem es einmal ausgeführt wurde. –

+0

Das Übergeben des Exit-Status des 'trap'ped-Befehls kann schwierig sein, wie' man bash' feststellt: "Der Rückgabestatus [von Trap] ist falsch, wenn irgendein Sigspec ungültig ist; andernfalls gibt trap true zurück." –

Antwort

3

Ihre erste Schlussfolgerung war richtig: Die ERR-Sig war zweimal passiert.

Während der ersten Ausführung von 'd' definieren Sie global einen Trap. Dies betrifft die nächsten Befehle (der aktuelle Aufruf von d ist nicht betroffen). Während der zweiten Ausführung von 'd' definieren Sie einen Trap erneut (nicht sehr nützlich), der Aufruf von 'false' schlägt fehl, daher führen wir den vom Trap definierten Handler aus. Dann kehren wir in der Parent-Shell zurück, wo auch 'd' fehlschlägt, also führen wir die Falle erneut aus.

Nur eine Bemerkung. ERR kann als 'sigspec Argument angegeben, aber ERR ist kein Signal ;-) Aus dem Handbuch von BASH:

If a sigspec is ERR, the command arg is executed whenever a sim‐ 
ple command has a non-zero exit status, subject to the following 
conditions. [...] 
These are the same conditions obeyed by the errexit option. 

Mit der Funktion ‚e‘, führt die ERR-Handler den Befehl ‚Echo‘, die erfolgreich . Deshalb schlägt die 'e'-Funktion nicht fehl, deshalb wird der ERR-Handler in diesem Fall nicht zweimal aufgerufen.

Wenn Sie versuchen "e; echo $?" Du wirst "0" lesen.

Dann habe ich Ihre "f" -Funktion versucht. Ich habe das gleiche Verhalten beobachtet (und ich war überrascht). Die Ursache ist NICHT eine schlechte Erweiterung von "$ s". Wenn Sie versuchen, einen Wert fest zu codieren, sollten Sie beachten, dass das Argument für die Anweisung 'return' ignoriert wird, wenn es vom Trap-Handler ausgeführt wird.

Ich weiß nicht, ob es ein normales Verhalten ist oder ob es ein Bug von BASH ist ...Oder vielleicht ein Trick, um eine Endlosschleife im Interpreter zu vermeiden :-)

Übrigens ist es meiner Meinung nach keine gute Verwendung von Trap. Wir können die Nebenwirkung der Falle vermeiden, indem wir eine Unterschale erstellen. In diesem Fall vermeiden wir den Fehler in der Eltern-Shell und wir behalten den Exitcode der inneren Funktion:

+1

BTW, 'g() (...)' - keine '{}' s überhaupt - ist eine tiefere Art, das zu schreiben. –

+0

Ich habe meine Antwort aktualisiert. Danke – mcoolive

Verwandte Themen