Implizite Rückgabe in Bash-Funktionen?


11

Angenommen, ich habe eine Bash-Funktion wie folgt:

gmx(){
  echo "foo";
}

Gibt diese Funktion implizit den Exit-Wert des echoBefehls zurück oder ist die Verwendung von return erforderlich?

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

Ich gehe davon aus, dass die Art und Weise, wie bash funktioniert, der Exit-Status des letzten Befehls der bash-Funktion derjenige ist, der "zurückgegeben" wird, aber nicht 100% sicher ist.

Antworten:


10

returnführt eine explizite Rückgabe von einer Shell-Funktion oder einem "Punktskript" (einem Quellenskript) durch. Wenn returnes nicht ausgeführt wird, erfolgt eine implizite Rückgabe am Ende der Shell-Funktion oder des Punktskripts.

Wenn returnes ohne Parameter ausgeführt wird, entspricht dies der Rückgabe des Exit-Status des zuletzt ausgeführten Befehls.

So returnfunktioniert das in allen POSIX-Shells.

Zum Beispiel,

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

ist daher gleichbedeutend mit

gmx () {
  echo 'foo'
  return
}

das ist das gleiche wie

gmx () {
  echo 'foo'
}

Im Allgemeinen ist es sehr selten, dass Sie $?überhaupt verwenden müssen. 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).


2
Ein Nachteil der Verwendung returnbesteht darin, dass für Funktionen, die wie definiert sind f() (...; cmd; return), die Optimierung verhindert wird, die einige Shells cmdausführen, wenn sie im selben Prozess wie die Subshell ausgeführt werden. Bei vielen Shells bedeutet dies auch, dass der Exit-Status der Funktion nicht die Informationen enthält, cmddie getötet wurden, als dies der Fall war (die meisten Shells können diese Informationen sowieso nicht abrufen).
Stéphane Chazelas

1
Beachten Sie, dass Sie mit pdksh und einigen seiner Ableitungen (wie OpenBSD shoder posh) benötigen würden, return -- "$?"wenn die Möglichkeit besteht, dass der letzte Befehl eine Funktion ist, die eine negative Zahl zurückgibt. mksh(ebenfalls basierend auf pdksh) verbietet Funktionen, negative Werte zurückzugeben.
Stéphane Chazelas

danke das hilft, ich glaube ich verstehe nicht wie return xandere funktionieren als exit x... das einzige was ich weiß ist, dass return xder aktuelle prozess nicht beendet wird.
Alexander Mills

@AlexanderMills Nun, es ist das, was ich gesagt habe: returnwird verwendet, um von einer Funktion oder einem Punktskript zurückzukehren. exitmacht etwas ganz anderes (beendet einen Prozess).
Kusalananda

Ja, das macht Sinn. Ich glaube, ich fange an, das besser in den Griff zu bekommen
Alexander Mills

7

Von der bash(1)Manpage:

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


richtig, und eine Konsequenz könnte sein, dass die return-Anweisung nichts anderes als der Exit-Status ist?
Alexander Mills

Ich denke, es returnist ein eingebauter Befehl - obwohl er return 1anders ist als exit 1usw.
Alexander Mills

1
"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) Erzwingt also returnden Exit-Status einer Funktion auf einen bestimmten Wert, falls angegeben.
Ignacio Vazquez-Abrams

1
@AlexandwrMills Ja, returnund exitbeide sind integriert, außer returnkönnen nur innerhalb der Funktion verwendet werden. Sie können ein Skript nicht mit beenden return. Der Beendigungsstatus ist der Wert, den der Befehl zurückgibt. returnist ein Befehl, der diesen Wert zurückgibt. "Return-Anweisung ist also nichts anderes als der Exit-Status" ist einfach nicht ganz korrekt. Einer ist ein Wert, der andere ist Befehl plus Wert.
Sergiy Kolodyazhnyy

1
@AlexanderMills, returnkehrt von der Funktion zurück und beendet exitdie gesamte Shell. Es ist genau das gleiche wie in, sagen wir C mit returnvs. exit(n)oder returnvs. sys.exit()in Python.
Ilkkachu

2

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

  • Obwohl returndie Shell aus syntaktischer Sicht eine ganz besondere Bedeutung hat, handelt es sich um einen in die Shell integrierten Befehl, und eine return-Anweisung wird wie jeder andere einfache Befehl analysiert. Das bedeutet also, dass, wie im Argument eines anderen Befehls, $?wenn es nicht zitiert wird, split + glob unterliegt

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

    return "$?"
  • returnin der Regel keine Option akzeptieren ( ksh93s nimmt 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 korrekt wiedergegeben wird, $?variiert auch von Shell zu Shell. Siehe Standard-Exit-Code, wenn der Prozess beendet wird. für Details dazu.

    Die meisten Shells akzeptieren negative Zahlen (schließlich ist das an den _exit()/ exitgroup()system-Aufruf übergebene Argument ein int, also mit Werten, die mindestens -2 31 bis 2 31 -1 umfassen, ist es nur sinnvoll, dass Shells für ihre Funktionen denselben Bereich akzeptieren). .

    Die meisten Muscheln verwenden die waitpid()und co. API zum Abrufen dieses Beendigungsstatus. In diesem Fall wird sie jedoch beim Speichern in auf eine Zahl zwischen 0 und 255 gekürzt$? . Auch wenn beim Aufrufen einer Funktion kein Prozess erzeugt und waitpid()zum Abrufen des Beendigungsstatus verwendet wird, da alles im selben Prozess ausgeführt wird, ahmen viele Shells dieses waitpid()Verhalten beim Aufrufen von Funktionen nach. Dies bedeutet, dass auch wenn Sie returnmit einem negativen Wert anrufen , $?eine positive Nummer enthalten ist.

    Nun, unter den Shells, returndie negative Zahlen akzeptieren (ksh88, ksh93, bash, zsh, pdksh und andere Derivate als mksh, yash), gibt es einige (pdksh und yash), die es so schreiben müssen, return -- -123wie es sonst -123als drei angenommen -1wird. -2, -3ungültige Optionen.

    Da pdksh und seine Ableitungen (wie OpenBSD shoder posh) die negative Zahl in beibehalten $?, bedeutet dies, dass das Ausführen return "$?"fehlschlägt, wenn $?eine negative Zahl enthalten ist (was passieren würde, wenn der letzte Ausführungsbefehl eine Funktion war, die eine negative Zahl zurückgibt).

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

    Zusammenfassend lässt sich sagen, dass Sie bei pdksh-basierten Shells möglicherweise negative Zahlen in Argumenten für Funktionen verwenden, aber wenn Sie dies tun, funktioniert dies return "$@"nicht. In anderen Shells return "$@"funktioniert dies und Sie sollten vermeiden, negative Zahlen (oder Zahlen außerhalb von 0..255) als Argumente für zu verwenden return.

  • In allen mir bekannten returnShells führt ein Aufruf aus einer Subshell, die in einer Funktion ausgeführt wird, dazu, dass die Subshell beendet wird (mit dem angegebenen Exit-Status, falls vorhanden, oder dem des letzten ausgeführten Befehls), andernfalls jedoch nicht, dass die Funktion zurückgegeben wird ( Für mich ist unklar, ob POSIX Ihnen diese Garantie gewährt. Einige argumentieren, dass exitanstelle von Exit-Subshells innerhalb von Funktionen verwendet werden sollte. Zum Beispiel

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

    wird ausgegeben:

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

0

Ja, der implizite Rückgabewert einer Funktion ist der Exit-Status des zuletzt ausgeführten Befehls. Dies gilt auch für jeden 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 dem erforderlichen Exit-Status zu beenden:

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

Und ja, die Erweiterung des Exit-Status muss angegeben werden:

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

A (exit 34)auch arbeiten.
Einige mögen argumentieren, dass ein robusteres Konstrukt sein sollte $(return 34)und dass ein Exit das ausgeführte Skript "beenden" sollte. Funktioniert aber $(return 34)nicht mit einer Version von Bash. Es ist also nicht tragbar.

Der sicherste Weg, einen Exit-Status festzulegen, besteht darin, ihn so zu verwenden, wie er zum Arbeiten, Definieren und returnAusführen einer Funktion entwickelt wurde:

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

Also am Ende einer Funktion. es ist genau gleichbedeutend, entweder nichts oder returnoder zu haben 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
}  

Wird drucken:

$ ./script
foo 78
baz 89
baz 90

Die einzige praktische Verwendung für "$?"besteht darin, entweder den Wert auszudrucken: echo "$?"oder ihn in einer Variablen zu speichern (da es sich um einen kurzlebigen Wert handelt und sich bei jedem ausgeführten Befehl ändert): exitstatus=$?(Denken Sie daran, die Variable in Befehlen wie anzugeben export EXITSTATUS="$?".

In dem returnBefehl liegt der gültige Wertebereich im Allgemeinen zwischen 0 und 255, es ist jedoch zu verstehen, dass die Werte von 126 + nvon einigen Shells verwendet werden, um einen speziellen Ausgangsstatus zu signalisieren. Daher wird generell empfohlen, 0-125 zu verwenden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.