Wie bekomme ich die Effekt und usefuless von "set -e" innerhalb eines shell-Funktion?
set -e
(oder ein Skript starten mit #!/bin/sh -e
) ist äußerst nützlich, um automatisch die Bombe aus, wenn es ein problem gibt. Es spart mir mit zu Fehler überprüfen jeden einzelnen Befehl, der fehlschlagen könnte.
Wie komme ich an das äquivalent von diesem innerhalb einer Funktion?
Ich habe zum Beispiel das folgende Skript aus, dass die Ausgänge sofort auf Fehler mit einer error-exit-status:
#!/bin/sh -e
echo "the following command could fail:"
false
echo "this is after the command that fails"
Die Ausgabe ist wie erwartet:
the following command could fail:
Nun möchte ich zum Abschluss noch in eine Funktion:
#!/bin/sh -e
my_function() {
echo "the following command could fail:"
false
echo "this is after the command that fails"
}
if ! my_function; then
echo "dealing with the problem"
fi
echo "run this all the time regardless of the success of my_function"
Erwartete Ausgabe:
the following command could fail:
dealing with the problem
run this all the time regardless of the success of my_function
Aktuelle Ausgabe:
the following output could fail:
this is after the command that fails
run this all the time regardless of the success of my_function
(ie. die Funktion ignoriert die set -e
)
Diese vermutlich zu erwartende Verhalten. Meine Frage ist: wie bekomme ich die Effekt und usefuless von set -e
in einem shell-Funktion? Ich möchte in der Lage sein, etwas nach oben, so dass ich nicht haben, um individuell Fehler kontrollieren Sie jeden Anruf, aber das Skript beim auftreten eines Fehlers beendet. Es sollte entspannen Sie den Stapel so weit wie nötig, bis ich tun, überprüfen Sie das Ergebnis, oder beenden Sie das Skript selbst wenn ich noch nicht überprüft. Dies ist, was set -e
schon, außer dass es keine nest.
Habe ich gefunden die gleiche Frage gebeten, außerhalb Stack-Überlauf, aber keine passende Antwort.
set -e
, aber innerhalb einer Funktion. Die andere Frage ist einfach, fragt etwa ähnlich überraschend Verhalten. Diese Frage hat weit mehr Stimmen, stars, Ansichten und nützliche Antworten für die verschiedenen alternativen, und ich denke, dass macht viel mehr Sinn offen zu halten, als der andere. Wenn überhaupt, dann markieren Sie das doppelte auf die andere Weise Runde.In aller fairness aber die Antwort auf die andere Frage ist sehr auf den Punkt und beantwortet die Frage, wie gut. Ich bin nicht bewandert genug in der bash, um zu entscheiden, was gehen sollte, wo und wie, aber wenn Sie ein gold-badge-Besitzer denkt, dass Weg, würde ich geneigt sein zu Folgen, die dupe Stimme.
Ich habe nichts gegen die andere Frage. Das Frage, jedoch ist hier für Entwickler, die zur Lösung der spezifischen Frage, die ich fragte. Es ist klar, dass es keine gute Antwort, aber alle Antworten hier etwas nützliches. Ich glaube nicht, dass es angemessen halten, diese Frage geschlossen, um neue Antworten, die vielleicht ebenso nützlich. Bietet, eine Antwort in der anderen Frage stattdessen verstecken Sie es wie die Frage fragt die eine subtil andere Frage ("Warum tut er das?" anstatt "Wie kann ich das erreichen?").
Ich habe bearbeitet den Titel (jetzt von der ursprünglichen Frage Körper), um zu versuchen, um dieses klarer.
Was ist falsch mit der Einstellung ein Fehler Falle, als pro das doppelte?
InformationsquelleAutor Robie Basak | 2010-11-01
Du musst angemeldet sein, um einen Kommentar abzugeben.
Aus der Dokumentation von
set -e
:In deinem Fall
false
ist ein Teil einer pipeline vorangestellt!
und ein Teilif
. So die Lösung ist, ändern Sie Ihren code so, dass er es nicht ist.In anderen Worten, es gibt nichts besonderes über Funktionen hier. Versuchen:
Es wird eine pipeline, obwohl eine Entartete. Wenn Sie das Kontrollkästchen mit der standard (insbesondere "2.10.2 Shell-Grammatik-Regeln"), werden Sie sehen, dass eine pipeline besteht aus mindestens einem Befehl (die mag einfach sein, die Verbindung von func.def.) vorangestellt bang anmelden. Es gibt keinen anderen Weg vorstellen, eine Negierung außer-pipeline.
Dies erklärt das Verhalten - danke - aber es löst nicht wirklich mein problem. Wie bekomme ich die Verhalten
set -e
, aber in diesem Fall in einer Funktion? Ich will schreiben, meine Funktion ist egal, ob die einzelnen einfachen Kommandos erfolgreich ausgeführt werden oder fehlschlagen, und die Funktion kehrt sofort zurück, die nicht null ist (vermutlich$?
) sobald einer dieser einfachen Befehle fehlschlägt. Als Gintautas Punkte in einer anderen Antwort, die Kombination mit&&
tun, aber ich möchte etwas, das bedeutet, dass für die Bequemlichkeit ich habe nicht zu ändern, der Körper der Funktion.Ich Schätze, warum du fragst, aber deine Anfrage nicht wirklich sinnvoll.
set -e
gelten für die Inhalte der Funktionen es sei denn wird die Funktion aufgerufen, in einer der Wege, ausgenommen vonset -e
, wie in der Dokumentation beschrieben Roman verknüpft.set -e
gilt nur für bestimmte Aufruf-Kontexten, also, Wenn Sie möchten, dass Ihre Funktion zurück, sobald etwas schief geht egal was Anhängen|| return
zu jedem Befehl (oder die Verkettung alles mit&&
) ist die standard-Lösung.Anders ausgedrückt:
set -e
ist fummelig Biest, und oft nicht wirklich, was Sie wollen, dass Ihr script zu tun, auch wenn es scheint wie ein wirklich nützliches hammer.InformationsquelleAutor Roman Cheplyaka
Können Sie direkt verwenden, um eine subshell, die als Ihre Funktion, definition, und legen Sie es sich sofort zu beenden, mit
set -e
. Dies würde den Umfang derset -e
um die Funktion subshell nur und später zu vermeiden, Umschalten zwischenset +e
undset -e
.Darüber hinaus können Sie eine variable Zuordnung in die
if
testen und dann echo das Ergebnis in einer zusätzlichenelse
- Anweisung.if ret=$( set -e; f );then
beendetf
früh mitdash -e
, aber nicht mitbash -e
. Ich definiertef() { echo a; false; echo "Should NOT get HERE"; }
, da wollte ich es testen mit normal-definierte Funktionen, nicht subshell Funktionen.InformationsquelleAutor philz
Dies ist ein bisschen ein Durcheinander, aber Sie tun können:
Diese funktionieren wird, wenn Ihre shell unterstützt die export -f (bash das auch tut).
Beachten Sie, dass dies nicht das Skript beendet. Das echo
nach dem false-in f wird nicht ausgeführt, noch wird der Körper
der, wenn, aber-Anweisungen nach dem if ausgeführt wird.
Wenn Sie eine shell, die nicht der Unterstützung der export -f, können Sie
Holen Sie sich die Semantik, die Sie wollen, durch ausführen von sh in der Funktion:
-f f
sah verwirrend. Wenn ich eine Funktionwhatsamacallit
, würde ichsh -ec whatsamacallit
um die Funktion wieder der erste Fehler?Ja, ersetzen
f
mit dem Namen der Funktion.InformationsquelleAutor William Pursell
Ich ging schließlich mit dieser, die anscheinend funktioniert. Ich habe versucht, die export-Methode auf den ersten, aber dann festgestellt, dass ich brauchte, um den export alle globalen (Konstante) Variablen das Skript verwendet.
Deaktivieren
set -e
wird, dann führen Sie den Aufruf einer Funktion innerhalb einer subshell, hatset -e
aktiviert. Speichern Sie die exit-status der subshell in eine variable, aktivieren Sie erneut "set-e", dann testen Sie die var.Können Sie nicht ausführen
f
als Teil einer pipeline, oder als Teil eines&&
von||
Befehlsliste (außer als letzten Befehl in der pipe oder Liste), oder als Bedingung in einerif
oderwhile
oder andere Zusammenhänge ignorierenset -e
. Dieser code kann auch nicht sein, in jedem dieser Kontexte, so dass, wenn Sie verwenden diese Funktion, Anrufer über die Verwendung der gleichen subshell /speichern-beenden-status Betrug. Diese Verwendung vonset -e
für die Semantik ähnlich wie werfen/fangen von Ausnahmen ist nicht wirklich geeignet für den Allgemeinen Gebrauch, angesichts der Einschränkungen und hart-zu-Lesen-syntax.trap err_handler_function ERR
hat die gleichen Einschränkungen wieset -e
ist, dass es nicht Feuer für Fehler in Kontexten, in denenset -e
nicht verlassen auf fehlgeschlagene Befehle.Sie vielleicht denken, dass die folgenden funktionieren würde, aber es funktioniert nicht:
set -e
nicht wirksam innerhalb der subshell, weil es merkt, dass es in der Bedingung einerif
. Dachte ich, dass einer subshell verändern würde, sondern nur in einer separaten Datei und läuft eine ganze separaten shell auf ihm arbeiten würde.if
,||
,&&
usw. 🙁netter aussehende Art und Weise zu schreiben, die den test:
if ((EXIT)); then echo "f failed"; fi
. Arithmetische Kontexte sind ganz nett für tun boolean Zeug.InformationsquelleAutor antak
Dieser Entwurf und POSIX-Spezifikation. Wir Lesen in
man bash
:daher sollten Sie vermeiden, sich auf
set -e
innerhalb von Funktionen.Gegeben das folgende BeispielAustin-Gruppe:
den
set -e
wird ignoriert, innerhalb der Funktion, denn die Funktion ist ein Befehl in einer UND-ODER andere Liste als die Letzte.Dem oben genannten Verhalten angegeben ist und von POSIX (siehe: Gewünschte Aktion):
InformationsquelleAutor kenorb
Kommen alle Befehle in Ihrer Funktion mit der
&&
Betreiber. Es ist nicht zu viel ärger und geben Sie das Ergebnis das Sie wollen.set -e
ist zu vermeiden, dies zu tun. Ich nehme die Antwort "es gibt keinen solchen Mechanismus", obwohl!set-e hat keine "springende Punkt", denn es ist ein Schlamassel. Ich benutze es die ganze Zeit, weil es mich gerettet eine Menge Zeit, viele Male, aber ich halte sehr niedrigen Erwartungen an es und so sollte jeder.
InformationsquelleAutor Gintautas Miliauskas
Ich weiß, das ist nicht das, was Sie gefragt, aber Sie können oder möglicherweise nicht bewusst, dass das Verhalten, das Sie suchen in "stellen". Jeder Teil einer "make" - Prozess, der fehlschlägt, bricht der Flucht. Es ist eine ganz andere Art von "Programmierung", obwohl, als shell scripting.
InformationsquelleAutor jcomeau_ictx
Müssen Sie die Funktion aufrufen, die in einer sub-shell (in den Klammern ()) um dies zu erreichen.
Ich denke, Sie wollen Ihr Skript so schreiben, wie diese:
Dann wird der Ausgang (wie gewünscht):
Wenn das script ausgeführt oben bekomme ich nur diese einzelne Zeile der Ausgabe:
the following command could fail:
. Das Skript scheint komplett beenden auf diefalse
Befehl was macht es unmöglich, zu implementieren der Fehlerbehandlung. Versucht es mit bash und dash.InformationsquelleAutor lothar