Implizite Rückgabe in Bash-Funktionen?

Angenommen, ich habe eine Bash-Funktion wie diese:

gmx(){ echo "foo"; } 

wird diese Funktion implizit ausgeführt Geben Sie den Exit-Wert des Befehls echo zurück oder ist die Verwendung von return erforderlich?

gmx(){ echo "foo"; return $? } 

Ich gehe davon aus, dass dies der Fall ist bash funktioniert, der Exit-Status des letzten Befehls der bash-Funktion wird „zurückgegeben“, ist aber nicht 100% sicher.

Antwort

return gibt eine explizite Rückgabe von einer Shell-Funktion oder einem“ Punktskript „(einem Quellenskript) aus. Wenn return nicht ausgeführt wird, erfolgt eine implizite Rückgabe am Ende der Shell-Funktion oder des Punktskripts.

Wenn return wird ohne Parameter ausgeführt. Dies entspricht der Rückgabe des Exit-Status des zuletzt ausgeführten Befehls.

So funktioniert return in allen POSIX-Versionen Shells.

Zum Beispiel entspricht

gmx () { echo "foo" return "$?" } 

daher

gmx () { echo "foo" return } 

entspricht

gmx () { echo "foo" } 

Im Allgemeinen ist es sehr selten, dass Sie $? überhaupt. Es wird wirklich nur benötigt, wenn Sie es für die zukünftige Verwendung speichern müssen, z. B. wenn Sie seinen Wert mehrmals untersuchen müssen (in diesem Fall würden Sie seinen Wert einer Variablen zuweisen und eine Reihe von Tests für diese Variable durchführen).

Kommentare

  • Ein Nachteil der Verwendung von return ist der für Funktionen wie f() (...; cmd; return) verhindert die Optimierung, die einige Shells durchführen, um die cmd im selben Prozess wie die Subshell auszuführen. Bei vielen Shells bedeutet dies auch, dass der Exit-Status der Funktion ‚ nicht die Information enthält, dass cmd getötet wurde, wenn dies der Fall war (Die meisten Shells können ‚ diese Informationen ohnehin nicht abrufen.)
  • Beachten Sie, dass mit pdksh und einigen seiner Ableitungen (wie OpenBSD sh oder posh), ‚ benötigen return -- "$?", wenn es eine gibt Chance, dass der letzte Befehl eine Funktion war, die eine negative Zahl zurückgegeben hat. mksh (ebenfalls basierend auf pdksh) verbietet Funktionen die Rückgabe negativer Werte.
  • danke dies hilft, ich denke ich Ich verstehe nicht, wie return x anders funktioniert als exit x … das einzige, was ich weiß, ist, dass return x beendet den aktuellen Prozess nicht.
  • @AlexanderMills Nun, ‚ ist das, was ich gesagt habe: return wird verwendet, um von einer Funktion oder einem Punktskript zurückzukehren. exit macht etwas völlig anderes (beendet einen Prozess).
  • Ja, das macht Sinn. Ich denke, ich fange an, dies besser in den Griff zu bekommen.

Antwort

Auf der Manpage bash(1):

Bei Ausführung ist der Exit-Status einer Funktion der Exit-Status des zuletzt im Body ausgeführten Befehls.

Kommentare

  • richtig, und eine Konsequenz könnte sein, dass die return-Anweisung nichts anderes als der Exit-Status ist?
  • Ich denke return ist ein eingebauter Befehl – obwohl return 1 sich von exit 1 usw. unterscheidet, also
  • “ return [n]: Bewirkt, dass eine Funktion die Ausführung beendet und den von n angegebenen Wert an ihren Aufrufer zurückgibt. Wenn n weggelassen wird, ist der Rückgabestatus der des letzten im Funktionskörper ausgeführten Befehls. “ (ibid) Also return erzwingt den Exit-Status einer Funktion auf einen bestimmten Wert, falls angegeben.
  • @AlexandwrMills Ja, return und exit sind beide integriert, außer dass return nur innerhalb der Funktion verwendet werden kann. Sie können ‚ ein Skript nicht mit return beenden. Der Beendigungsstatus ist der Wert, den der Befehl zurückgibt. return ist ein Befehl, der diesen Wert zurückgibt. “ return-Anweisung ist also nichts anderes als der Exit-Status “ ist einfach nicht ganz genau. Einer ist ein Wert, der andere ist Befehl plus Wert.
  • @AlexanderMills, return gibt von der Funktion zurück, exit verlässt die gesamte Shell. Es ist ‚ genau das gleiche wie in, sagen Sie C mit return vs. exit(n), oder return vs. sys.exit() in Python.

Antwort

Ich werde den bereits gegebenen Antworten nur ein paar Hinweise zur Vorsicht hinzufügen:

  • Obwohl return aus syntaktischer Sicht eine ganz besondere Bedeutung für die Shell hat, handelt es sich um einen in die Shell integrierten Befehl und eine return-Anweisung wird wie jeder andere einfache Befehl analysiert. Dies bedeutet, dass $?, wenn sie nicht in Anführungszeichen gesetzt ist, wie im Argument eines anderen Befehls split + glob

    Sie müssen also $? zitieren, um dies zu vermeiden:

    return "$?" 
  • return akzeptiert normalerweise keine Option (ksh93 „s akzeptiert die üblichen --help, --man, --author … obwohl). Das einzige erwartete Argument (optional) ist der Rückkehrcode. Der Bereich der akzeptierten Rückkehrcodes variiert von Shell zu Shell und ob ein Wert außerhalb von 0..255 in

variiert ebenfalls von Shell zu Shell. Weitere Informationen hierzu finden Sie unter Standard-Exit-Code, wenn der Prozess beendet wird? .

Die meisten Shells akzeptieren negative Zahlen (schließlich wurde das Argument an übergeben Der Systemaufruf _exit() / exitgroup() ist ein int, also mit Werten, die mindestens – 2 31 bis 2 31 -1, daher ist es nur sinnvoll, dass Shells den gleichen Bereich für ihre Funktionen akzeptieren.

Die meisten Shells verwenden das waitpid() und co. API zum Abrufen dieses Beendigungsstatus. In diesem Fall wird sie jedoch auf eine Zahl zwischen 0 und 255 gekürzt, wenn in $? gespeichert wird. Auch wenn eine Funktion aufgerufen wird beinhaltet nicht das Laichen eines Prozesses und verwendet waitpid(), um seinen Exit-Status abzurufen, da alles im selben Prozess ausgeführt wird. Viele Shells ahmen auch nach, dass waitpid() Verhalten beim Aufrufen von Funktionen. Dies bedeutet, dass $? auch dann eine positive Zahl enthält, wenn Sie return mit einem negativen Wert aufrufen.

Nun, unter den Shells, deren return negative Zahlen akzeptiert (ksh88, ksh93, bash, zsh, pdksh und andere Ableitungen als mksh, yash), gibt es einige ( pdksh und yash), die als return -- -123 geschrieben werden müssen, andernfalls wird -123 als drei -1, -2, -3 ungültige Optionen.

Wie pdksh und sein de Rivative (wie OpenBSD sh oder posh) behalten die negative Zahl in $? bei Das Ausführen von return "$?" würde fehlschlagen, wenn $? eine negative Zahl enthält (was passieren würde, wenn der letzte Ausführungsbefehl eine Funktion wäre, die eine negative Zahl zurückgibt ).

return -- "$?" wäre in diesen Shells besser. Beachten Sie jedoch, dass diese Syntax zwar von den meisten Shells unterstützt wird, jedoch nicht POSIX ist und in der Praxis nicht von mksh und Aschederivaten unterstützt wird.

Zusammenfassend lässt sich also sagen, mit Bei pdksh-basierten Shells können Sie negative Zahlen in Argumenten für Funktionen verwenden. Wenn Sie dies jedoch tun, funktioniert return "$@" nicht. In anderen Shells return "$@" funktioniert und Sie sollten vermeiden, negative Zahlen (oder Zahlen außerhalb von 0..255) als Argumente für return zu verwenden.

  • In allen mir bekannten Shells führt das Aufrufen von return aus einer in einer Funktion ausgeführten Subshell dazu, dass die Subshell beendet wird (mit dem angegebenen Exit-Status, falls vorhanden, oder dem des letzten Befehls run), führt aber ansonsten nicht zu einer Rückkehr der Funktion (für mich ist unklar, ob POSIX Ihnen diese Garantie gewährt. Einige argumentieren, dass exit anstelle von Exit-Subshells verwendet werden sollte Innenfunktionen). Zum Beispiel gibt

    f() { (return 3) echo "still inside f. Exit status: $?" } f echo "f exit status: $?" 

    Folgendes aus:

    still inside f. Exit status: 3 f exit status: 0 
  • Antwort

    Ja, der implizite Rückgabewert einer Funktion ist der Exit-Status des zuletzt ausgeführten Befehl. Das gilt auch an jedem Punkt eines Shell-Skripts. Zu jedem Zeitpunkt in der Skriptausführungssequenz ist der aktuelle Beendigungsstatus der Beendigungsstatus des zuletzt ausgeführten Befehls. Sogar Befehl, der als Teil einer Variablenzuweisung ausgeführt wird: var=$(exit 34). Der Unterschied zu Funktionen besteht darin, dass eine Funktion den Exit-Status am Ende der Ausführung der Funktion ändern kann.

    Die alternative Möglichkeit, den „aktuellen Exit-Status“ zu ändern, besteht darin, eine Sub-Shell zu starten und mit zu beenden Erforderlicher Exit-Status:

    $ $(exit 34) $ echo "$?" 34 

    Und ja, der Exit-Status Erweiterung muss in Anführungszeichen gesetzt werden:

    $ IFS="123" $ $(exit 34) $ echo $? 4 

    A (exit 34) funktioniert ebenfalls.
    Einige mögen argumentieren, dass ein robusteres Konstrukt $(return 34) sein sollte und dass ein Exit das ausgeführte Skript „beenden“ sollte. $(return 34) funktioniert jedoch nicht mit einer -Version von bash. Es ist also nicht portabel.

    Der sicherste Weg, einen Exit-Status festzulegen, besteht darin, ihn so zu verwenden, wie er für die Arbeit, Definition und return einer Funktion entwickelt wurde :

    exitstatus(){ return "${1:-"$?"}"; } 

    Also am Ende einer Funktion. Es ist genau gleichbedeutend mit entweder nichts oder return oder return "$?". Das Ende einer Funktion muss nicht die „letzte Codezeile einer Funktion“ bedeuten.

    #!/bin/sh exitstatus(){ a="${1:-"$?"}"; return "$a"; } gmx(){ if [ "$1" = "one" ]; then printf "foo "; exitstatus 78 return "$?" elif [ "$1" = "two" ]; then printf "baz "; exitstatus 89 return else printf "baz "; exitstatus 90 fi } 

    Gibt Folgendes aus:

    $ ./script foo 78 baz 89 baz 90 

    Die einzige praktische Verwendung für "$?" besteht darin, entweder den Wert echo "$?" zu drucken oder zu speichern es in einer Variablen (da es ein kurzlebiger Wert ist und sich mit jedem ausgeführten Befehl ändert): exitstatus=$? (denken Sie daran, die Variable in Befehlen wie export EXITSTATUS="$?".

    Im Befehl return liegt der gültige Wertebereich im Allgemeinen zwischen 0 und 255, aber verstehen Sie die Werte von 126 + n werden von einigen Shells verwendet, um einen speziellen Ausgangsstatus zu signalisieren. Daher wird generell empfohlen, 0-125 zu verwenden.

    Schreibe einen Kommentar

    Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.