Ich habe in letzter Zeit einige seltsame Probleme mit Bash. Während ich versuchte, mein Skript zu vereinfachen, kam ich auf dieses kleine Stück Code:
$ o(){ echo | while read -r; do return 0; done; echo $?;}; o
0
$ o(){ echo | while read -r; do return 1; done; echo $?;}; o
1
return
sollte die Funktion verlassen haben, ohne zu drucken $?
, nicht wahr? Nun, dann habe ich geprüft, ob ich alleine von einer Pipe zurückkehren kann:
$ echo | while read -r; do return 1; done
bash: return: can only `return' from a function or sourced script
Das gleiche passiert ohne while
Schleife:
$ foo(){ : | return 1; echo "This should not be printed.";}
$ foo
This should not be printed.
Fehlt mir hier etwas? Eine Google-Suche hat dazu nichts gebracht! Meine Bash-Version ist 4.2.37 (1) -Release auf Debian Wheezy.
bash
shell-script
pipe
subshell
Teresa und Junior
quelle
quelle
while
nicht für die Reproduktion benötigt wird? Es lenkt vom Punkt ab.while
Schleife ist eine sehr häufige Verwendung für eine Pipe mitreturn
. Das zweite Beispiel ist direkter, aber es ist etwas, von dem ich nicht glaube, dass es jemals jemand verwenden würde ...Antworten:
Verwandte Themen: /programming//a/7804208/4937930
Es ist kein Fehler, dass Sie ein Skript nicht beenden oder von einer Funktion durch
exit
oderreturn
in Subshells zurückkehren können. Sie werden in einem anderen Prozess ausgeführt und wirken sich nicht auf den Hauptprozess aus.Außerdem, nehme ich an, sehen Sie undokumentierte Verhaltensweisen von Bash auf (wahrscheinlich) undefinierten Spezifikationen. In einer Funktion werden
return
auf oberster Ebene von Subshell-Befehlen keine Fehler gemeldet, und sie verhält sich einfach soexit
.IMHO ist es ein Bash-Bug für das inkonsistente Verhalten,
return
je nachdem, ob sich die Hauptanweisung in einer Funktion befindet oder nicht.Ausgabe:
quelle
return
eine Befehlssequenz auf oberster Ebene in einer Subshell nicht funktioniert und insbesondere die Subshell nicht beendet, hat mich bereits zu den Erwartungen bestehender Dokumente veranlasst. Das OP kann dort eingesetzt werden,exit 1 || return 1
wo es verwendet werden sollreturn
, und sollte dann das erwartete Verhalten aufweisen. BEARBEITEN: Die Antwort von @ Herbert zeigt an, dass die oberste Ebenereturn
in der Unterschale alsexit
(aber nur von der Unterschale) fungiert.return
in einer einfachen Subshell-Sequenz sollte in jedem Fall als Laufzeitfehler behauptet werden , aber eigentlich ist es nicht, wenn es in einer Funktion auftritt. Dieses Problem wurde auch in gnu.bash.bug diskutiert , aber es gibt keine Schlussfolgerung.return
Aussage funktionsfähig und damit legal. Das resultierende Verhalten ist jedoch nicht spezifiziert.Es ist kein Bug in,
bash
sondern das dokumentierte Verhalten :Die
return
Anweisung ist gültig, wenn sie sich in einer Funktionsdefinition befindet, aber auch in einer Subshell. Sie wirkt sich nicht auf die übergeordnete Shell aus, sodass die nächste Anweisungecho
unabhängig davon ausgeführt wird. Es handelt sich jedoch um eine nicht portierbare Shell-Konstruktion, da der POSIX-Standard die Ausführung der Befehle, aus denen eine Pipeline besteht, entweder in einer Subshell (Standardeinstellung) oder in der obersten Shell (zulässige Erweiterung) ermöglicht.Hoffentlich können Sie
bash
mit ein paar Optionen festlegen, wie Sie es erwarten:quelle
return
die Funktion nicht beendet wird, ist es nicht sinnvoller, wenn die Shell nur gedruckt wirdbash: return: can only `return' from a function or sourced script
, anstatt dem Benutzer ein falsches Gefühl zu vermitteln, dass die Funktion möglicherweise zurückgegeben wurde.return
von einer Subshell ausführen . Schließlich weiß es, dass es sich um eine Subshell handelt, wie die$BASH_SUBSHELL
Variable belegt. Das größte Problem ist, dass dies zu Fehlalarmen führen kann. ein Benutzer, der versteht , wie Subshells Arbeit Skripte geschrieben haben könnte , dass die Verwendungreturn
von anstelleexit
einer Sub - Shell zu beenden. (Und natürlich gibt es gültige Fälle, in denen man Variablen setzen odercd
in einer Subshell ausführen möchte.)return
kehrt von der Subshell zurück, anstatt fehlzuschlagen, da sie sich in einer tatsächlichen Funktion befindet. Das Problem ist, dasshelp return
Folgendes konkret angegeben wird:Causes a function or sourced script to exit with the return value specified by N.
Jeder Benutzer erwartet, dass die Dokumentation mindestens fehlschlägt oder eine Warnung ausgibt, sich jedoch niemals so verhältexit
.return
in einer Subshell in einer Funktion von der Funktion zurückkehrt (im Haupt-Shell-Prozess), Subshells nicht sehr gut versteht. Umgekehrt würde ich von einem Leser, der Subshells versteht, erwarten, dass erreturn
in einer Subshell eine Funktion zum Beenden der Subshell erwartet, genau wieexit
dies der Fall wäre.Laut POSIX-Dokumentation ist die Verwendung
return
von Skripten außerhalb der Funktionen oder Quellen nicht spezifiziert . Es hängt also von Ihrer Shell ab, wie Sie damit umgehen.Die SystemV-Shell meldet einen Fehler, während sich innerhalb
ksh
,return
außerhalb der Funktion oder des Quellenskripts wie verhaltenexit
. Die meisten anderen POSIX-Shells und Schilys verhalten sich ebenfalls so:ksh
undzsh
wurde nicht ausgegeben, weil der letzte Teil der Pipe in diesen Shells in der aktuellen Shell anstelle der Subshell ausgeführt wurde. Die return-Anweisung wirkte sich auf die aktuelle Shell-Umgebung aus, die die Funktion aufrief, und veranlasste die Funktion, sofort zurückzukehren, ohne etwas zu drucken.In der interaktiven Sitzung
bash
nur den Fehler melden, die Shell jedoch nicht beendet,schily's osh
den Fehler gemeldet und die Shell beendet:(
zsh
In der interaktiven Sitzung und Ausgabe wird das Terminal nicht beendetbash
,yash
undschily's osh
der Fehler wurde gemeldet, die Shell wurde jedoch nicht beendet.)quelle
return
hier innerhalb einer Funktion verwendet wird.return
war die Verwendung innerhalb Subshell innen Funktion , mit der Ausnahmeksh
undzsh
.Ich denke, dass Sie das erwartete Verhalten haben, in der Bash wird jeder Befehl in einer Pipeline in einer Subshell ausgeführt. Sie können sich überzeugen, indem Sie versuchen, eine globale Variable Ihrer Funktion zu ändern:
Übrigens funktioniert die Rückkehr, aber sie kehrt von der Unterschale zurück. Auch hier können Sie Folgendes überprüfen:
Gibt Folgendes aus:
Die return-Anweisung hat die Subshell also korrekt verlassen
.
quelle
foo(){ : | return 1 || return 2; echo$?; echo "This should not be printed.";}; foo; echo $?
Sie daher, um die Funktion zu beenden, und Sie erhalten das Ergebnis von2
. Aber der Klarheit halber würde ich dasreturn 1
sein lassenexit 1
.Die allgemeinere Antwort ist, dass Bash und einige andere Shells normalerweise alle Elemente einer Pipeline in separate Prozesse einteilen. Dies ist sinnvoll, wenn die Befehlszeile ist
da Programme normalerweise sowieso in getrennten Prozessen ausgeführt werden (sofern Sie nicht sagen ). Aber es kann eine Überraschung sein
exec program
Dabei sind einige oder alle Befehle integrierte Befehle. Triviale Beispiele sind:
Ein etwas realistischeres Beispiel ist
wobei das gesamte
while
...do
...done
Schleife in eine Unterprozess gesetzt wird, und so seine Änderungent
an den Hauptschale , nachdem die Schleifenenden sind nicht sichtbar. Und genau das tun Sie, indem Sie in einewhile
Schleife leiten, die Schleife als Subshell ausführen und dann versuchen, von der Subshell zurückzukehren.quelle