Frage Was macht 'set -e', und warum könnte es als gefährlich angesehen werden?


Diese Frage ist bei einem Pre-Interview-Quiz erschienen und macht mich verrückt. Kann jemand das beantworten und mich beruhigen? Das Quiz hat keinen Bezug zu einer bestimmten Shell, aber die Jobbeschreibung bezieht sich auf ein Unix sa. wieder ist die Frage einfach ...

Was macht 'set -e', und warum könnte es als gefährlich angesehen werden?


141
2018-05-19 16:39


Ursprung


Hier ist ein verwandter Thread: stackoverflow.com/questions/64786/error-handling-in-bash/... - Stefan Lasiewski


Antworten:


set -e bewirkt, dass die Shell beendet wird, wenn ein Unterbefehl oder eine Pipeline einen Status ungleich Null zurückgibt.

Die Antwort, nach der der Interviewer gesucht hat, ist:

Es wäre gefährlich, "set -e" beim Erstellen von init.d-Skripten zu verwenden:

Von http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2 -

Seien Sie vorsichtig bei der Verwendung von set -e in init.d-Skripten. Das Schreiben korrekter init.d-Skripts erfordert das Akzeptieren verschiedener Fehlerausgabestatus, wenn Daemons bereits ausgeführt werden oder bereits gestoppt wurden, ohne das Skript init.d abzubrechen, und gemeinsame init.d-Funktionsbibliotheken können nicht sicher mit set -e aufgerufen werden. Bei init.d-Skripten ist es oft einfacher, set -e nicht zu verwenden und stattdessen das Ergebnis jedes Befehls separat zu überprüfen.

Dies ist eine aus Sicht des Interviewer gültige Frage, da hier die Kenntnisse der Kandidaten für das Skripting und die Automatisierung auf Serverebene überprüft werden


146
2017-08-09 21:01



schöner Fund. Vielen Dank. - egorgry
guter Punkt. Es würde den Boot-Prozess über etwas anhalten, das technisch gesehen ein Fehler sein könnte, sollte aber nicht das ganze Skript zum Stillstand bringen - Matt
Obwohl ich damit einverstanden bin stackoverflow.com/questions/78497/...Ich denke, dass dieser Stil eine gute Übereinstimmung mit bash für kurze init-checks und Logging oder andere Umgebung Affe Patching vor dem Ausführen der Ziel-Workload findet. Wir verwenden diese Richtlinie für unsere Docker-Image-Init-Skripte. - joshperry


Von bash(1):

          -e      Exit immediately if a pipeline (which may consist  of  a
                  single  simple command),  a subshell command enclosed in
                  parentheses, or one of the commands executed as part  of
                  a  command  list  enclosed  by braces (see SHELL GRAMMAR
                  above) exits with a non-zero status.  The shell does not
                  exit  if  the  command that fails is part of the command
                  list immediately following a  while  or  until  keyword,
                  part  of  the  test  following  the  if or elif reserved
                  words, part of any command executed in a && or  ││  list
                  except  the  command  following  the final && or ││, any
                  command in a pipeline but the last, or if the  command’s
                  return  value  is being inverted with !.  A trap on ERR,
                  if set, is executed before the shell exits.  This option
                  applies to the shell environment and each subshell envi-
                  ronment separately (see  COMMAND  EXECUTION  ENVIRONMENT
                  above), and may cause subshells to exit before executing
                  all the commands in the subshell.

Leider bin ich nicht kreativ genug, um darüber nachzudenken, warum es gefährlich wäre, außer "der Rest des Skripts wird nicht ausgeführt werden" oder "es könnte möglicherweise echte Probleme maskieren".


33
2018-05-19 16:43



mask real / andere probleme, yeah, ich schätze, ich konnte das sehen ... ich hatte Mühe, ein Beispiel dafür zu finden, dass es auch gefährlich ist ... - cpbills
Da ist die Manpage für set! Ich lande immer bei builtin(1). Vielen Dank. - Jared Beck
Wie würde ich wissen, dass die Dokumentation für set ist zu finden man 1 bash?? Und wie könnte jemand das finden? -e Option für die set Stichwort in einer Handbuchseite, die so enorm groß ist? Du kannst nicht /-e Suche hier - Blauhirn
@Blauhirn benutzen help set - Blauhirn


Es ist darauf hinzuweisen, dass set -e kann für verschiedene Abschnitte eines Skripts ein- und ausgeschaltet werden. Es muss nicht für die Ausführung des gesamten Skripts aktiviert sein. Es könnte sogar bedingt aktiviert werden. Das heißt, ich benutze es nie, da ich meine eigene Fehlerbehandlung (oder nicht) mache.

some code
set -e     # same as set -o errexit
more code  # exit on non-zero status
set +e     # same as set +o errexit
more code  # no exit on non-zero status

Bemerkenswert ist auch das aus dem Bash Man Seitenbereich auf der trap Befehl, der auch beschreibt, wie set -e funktioniert unter bestimmten Umständen.

Das                 ERR Trap wird nicht ausgeführt, wenn der fehlgeschlagene Befehl Teil des Befehls ist                 Befehlsliste unmittelbar nach einer Weile oder bis zum Schlüsselwort,                 Teil des Tests in einer if-Anweisung, Teil eines Befehls ausgeführt                 in einer && oder ⎪⎪ Liste, oder wenn der Rückgabewert des Befehls ist                 invertiert via!. Dies sind die gleichen Bedingungen, die von der                 Errexit-Option.

Es gibt also einige Bedingungen, unter denen ein Nicht-Null-Status keinen Ausgang verursacht.

Ich denke, die Gefahr besteht darin, nicht zu verstehen, wann set -e kommt ins Spiel und wenn nicht und unter falscher Annahme falsch.

Bitte sehen Sie auch BashFAQ / 105 Warum setzt nicht -e (oder setze -o errexit oder trap ERR) was ich erwartet habe?


19
2018-05-19 22:39



Obwohl ich von der Frage ein wenig abwich, ist diese Antwort genau das, wonach ich suche: Ausschalten nur für einen kleinen Teil eines Skripts! - Stephan Bijzitter


Denken Sie daran, dies ist ein Quiz für ein Vorstellungsgespräch. Die Fragen wurden möglicherweise von den derzeitigen Mitarbeitern verfasst und können falsch sein. Das ist nicht unbedingt schlecht, und alle machen Fehler, und Interviewfragen sitzen oft ohne Rückschau in einer dunklen Ecke und kommen nur während eines Interviews.

Es ist durchaus möglich, dass "set -e" nichts tut, was wir als "gefährlich" bezeichnen würden. Aber der Autor dieser Frage mag fälschlicherweise glauben, dass "set -e" aufgrund ihrer eigenen Ignoranz oder Voreingenommenheit gefährlich ist. Vielleicht haben sie ein fehlerhaftes Shell-Skript geschrieben, es wurde furchtbar bombardiert, und fälschlicherweise dachten sie, dass "set -e" schuld war, als sie es tatsächlich versäumten, eine korrekte Fehlerüberprüfung zu schreiben.

Ich habe in den letzten 2 Jahren an 40 Vorstellungsgesprächen teilgenommen und die Interviewer stellen manchmal Fragen, die falsch sind, oder haben falsche Antworten.

Oder vielleicht ist es eine Trickfrage, die lahm wäre, aber nicht völlig unerwartet.

Oder vielleicht ist das eine gute Erklärung: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html


13
2018-05-19 17:03



+1 Ich bin im selben Boot, und viele der "technischen" Interviews, mit denen ich zu tun habe, sind zumindest leicht fehlgeleitet. - cpbills
Beeindruckend. Gut gefunden auf der Debian-Liste. +1 für die Ignoranz von Interviewfragen. Ich erinnere mich daran, dass ich einmal eine Netback-Antwort argumentierte, da ich zu 100% sicher war, dass ich recht hatte. Sie sagten nein. Ich ging nach Hause und googelte es, ich hatte Recht. - egorgry


set -e weist bash in einem Skript an, jedesmal zu beenden, wenn irgendetwas einen Rückgabewert ungleich Null zurückgibt.

Ich konnte sehen, wie das nervig wäre, und fehlerhaft, nicht sicher über gefährlich, es sei denn, Sie hatten Berechtigungen für etwas geöffnet, und bevor Sie sie wieder einschränken konnten, starb Ihr Skript.


9
2018-05-19 16:46



Das ist interessant. Ich dachte nicht daran, dass Berechtigungen in einem Skript geöffnet werden, das vorzeitig stirbt, aber ich könnte sehen, dass das als gefährlich angesehen wird. Der spaßige Teil dieses Quiz ist, dass Sie kein Referenzmaterial wie man oder google verwenden können und wenn Sie nicht vollständig antworten können, antworten Sie es überhaupt nicht. - egorgry
das ist nur albern, ich würde diesen arbeitgeber überdenken ... scherze (irgendwie). Es ist gut, eine starke Basis an Wissen zu haben, aber die Hälfte der IT-Arbeit ist Wissen / wo / um die Informationen zu finden ... hoffentlich waren sie schlau genug, dies bei der Bewertung von Bewerbern zu berücksichtigen. Auf einer Seitennotiz sehe ich / no / use für set -ein der Tat, für mich spricht es von Faulheit, Fehler in Ihren Skripten zu ignorieren ... also behalten Sie das im Hinterkopf, auch bei diesem Arbeitgeber ... wenn sie es oft benutzen, wie sehen ihre Skripte aus, dass Sie wird unweigerlich beibehalten müssen ... - cpbills
ausgezeichneter Punkt @cpbills. Ich sehe auch keine Verwendung für Set -e in einem Drehbuch und es ist wahrscheinlich, warum es mich so überhäuft hat. Ich würde gerne alle Fragen posten, da einige wirklich gut sind und einige wirklich verrückt und zufällig wie diese sind. - egorgry
Ich habe es in vielen System Cron Jobs gesehen ... - Andrew


set -e beendet das Skript, wenn ein Exit-Code ungleich Null auftritt, außer unter bestimmten Bedingungen. Um die Gefahren seiner Verwendung in wenigen Worten zusammenzufassen: Es verhält sich nicht so, wie die Leute denken.

Meiner Meinung nach sollte es als gefährlicher Hack angesehen werden, der nur zu Kompatibilitätszwecken existiert. Das set -e Die Anweisung wandelt die Shell nicht von einer Sprache, die Fehlercodes verwendet, in eine Sprache um, die einen ausnahmebedingten Kontrollfluss verwendet. Sie versucht nur schlecht, dieses Verhalten zu emulieren.

Greg Wooledge hat eine Menge zu den Gefahren zu sagen set -e:

In der zweiten Verbindung gibt es verschiedene Beispiele für das nicht intuitive und unvorhersehbare Verhalten von set -e.

Einige Beispiele für das nicht intuitive Verhalten von set -e (einige stammen aus dem Wiki-Link oben):

  • Stellen -e
    x = 0
    lass x ++
    echo "x ist $ x"
    Dies führt dazu, dass das Shell-Skript vorzeitig beendet wird, weil let x++ gibt 0 zurück, was von der let Schlüsselwort als Falsy-Wert und wird in einen Exit-Code ungleich Null umgewandelt. set -e bemerkt dies und beendet das Skript stillschweigend.
  • Stellen -e
    [-d / opt / foo] && echo "Warnung: foo ist bereits installiert. Wird überschrieben." > & 2
    echo "Installieren von foo ..."
    

    Das oben genannte funktioniert wie erwartet und es wird eine Warnung ausgegeben /opt/foo existiert schon.

    Stellen -e
    check_previous_install () {
        [-d / opt / foo] && echo "Warnung: foo ist bereits installiert. Wird überschrieben." > & 2
    }
    
    check_previous_install
    echo "Installieren von foo ..."
    

    Obiges, obwohl der einzige Unterschied darin besteht, dass eine einzelne Zeile in eine Funktion umgestaltet wurde, wird if enden /opt/foo ist nicht vorhanden. Dies liegt daran, dass die Tatsache, dass es ursprünglich funktioniert hat, eine besondere Ausnahme darstellt set -edas Verhalten. Wann a && b gibt nicht null zurück, wird von ignoriert set -e. Jetzt, da es sich um eine Funktion handelt, entspricht der Exit-Code der Funktion dem Exit-Code dieses Befehls, und die Funktion, die einen Wert ungleich Null zurückgibt, beendet das Skript stillschweigend.

  • Stellen -e
    IFS = $ '\ n' gelesen -d '' -r -a config_vars <Konfig
    

    Das obige liest das Array config_vars aus der Datei config. Wie der Autor beabsichtigt, endet es mit einem Fehler wenn config wird vermisst. Wie der Autor vielleicht nicht beabsichtigt, beendet es still, wenn config endet nicht in einer Zeilenumbruch. Ob set -e wurden hier nicht benutzt config_vars würde alle Zeilen der Datei enthalten, unabhängig davon, ob sie in einem Zeilenumbruch endete oder nicht.

    Benutzer von Sublime Text (und anderen Text-Editoren, die Zeilenumbrüche falsch behandeln), seien Sie vorsichtig.

  • Stellen -e
    
    sollte_audit_user () {
        lokale Gruppengruppen = "$ (Gruppen" $ 1 ")"
        für Gruppe in $ Gruppen; tun
            if ["$ group" = Audit]; dann gebe 0 zurück; fi
        erledigt
        zurück 1
    }
    
    wenn should_audit_user "$ user"; dann
        Logger 'Blah'
    fi
    

    Der Autor hier könnte vernünftigerweise erwarten, dass, wenn aus irgendeinem Grund der Benutzer $user existiert nicht, dann die groups Der Befehl wird fehlschlagen und das Skript wird beendet, anstatt dass der Benutzer eine Aufgabe ungeprüft ausführen muss. In diesem Fall jedoch set -e Kündigung wird nie wirksam. Ob $user kann aus irgendeinem Grund nicht gefunden werden, anstatt das Skript zu beenden, das should_audit_user Funktion wird nur falsche Daten als ob zurückgeben set -e war nicht in Kraft.

    Dies gilt für jede Funktion, die aus dem Bedingungsteil von an aufgerufen wird if Aussage, egal wie tief verschachtelt, egal wo es definiert ist, egal, auch wenn Sie laufen set -e drinnen wieder. Verwenden if zu irgendeinem Zeitpunkt vollständig deaktiviert die Wirkung von set -e bis der Bedingungsblock vollständig ausgeführt ist. Wenn sich der Autor dieser Fallstricke nicht bewusst ist oder seinen gesamten Call-Stack nicht in allen möglichen Situationen kennt, in denen eine Funktion aufgerufen werden kann, dann schreiben sie Buggy-Code und das falsche Sicherheitsgefühl von set -e wird zumindest teilweise schuld sein.

    Selbst wenn sich der Autor dieses Problems bewusst ist, besteht die Problemumgehung darin, Code so zu schreiben, wie man es ohne schreiben würde set -eEffektives Rendern dieses Schalters weniger als nutzlos; Der Autor muss nicht nur manuelle Fehlerbehandlungscodes schreiben set -e waren nicht in Kraft, aber die Anwesenheit von set -e Vielleicht haben sie sie dazu gebracht zu denken, dass sie das nicht müssen.

Einige weitere Nachteile von set -e:

  • Es fördert schlampigen Code. Fehlerhandler werden komplett vergessen, in der Hoffnung, dass jeder Fehler den Fehler auf eine vernünftige Art und Weise meldet. Mit Beispielen wie let x++ oben ist dies nicht der Fall. Wenn das Skript unerwartet beendet wird, ist es normalerweise still, was das Debuggen behindert. Wenn das Skript nicht stirbt und Sie es erwartet haben (siehe vorherigen Aufzählungspunkt), dann haben Sie einen subtileren und heimtückischen Fehler in Ihren Händen.
  • Es führt die Menschen in ein falsches Gefühl der Sicherheit. Siehe noch einmal die if-Konditionspunkt.
  • Die Orte, an denen die Shell endet, sind nicht konsistent zwischen Shell- oder Shell-Versionen. Es ist möglich, versehentlich ein Skript zu schreiben, das sich auf Grund des Verhaltens von einer älteren Version von bash anders verhält set -e zwischen diesen Versionen optimiert worden.

set -e ist ein umstrittenes Thema, und einige Leute, die sich der damit verbundenen Probleme bewusst sind, empfehlen dagegen, während einige andere nur empfehlen, vorsichtig zu sein, während sie aktiv sind, um die Fallstricke zu kennen. Es gibt viele Shell-Scripting-Neulinge, die empfehlen set -eauf alle Skripte als ein Sammelbegriff für Fehlerbedingungen, aber im wirklichen Leben funktioniert es nicht so.

set -e ist kein Ersatz für Bildung.


5
2018-04-27 23:06





Ich würde sagen, es ist gefährlich, weil du den Fluss deines Skripts nicht mehr kontrollierst. Das Skript kann so lange beendet werden, wie einer der Befehle, die das Skript aufruft, einen Wert ungleich Null zurückgibt. Alles, was Sie tun müssen, ist etwas zu tun, das das Verhalten oder die Ausgabe einer der Komponenten verändert, und Sie beenden das Hauptskript. Es könnte eher ein Stilproblem sein, aber es hat definitiv Konsequenzen. Was, wenn dieses Hauptskript eine Flagge setzen sollte, und das nicht, weil es früh beendet wurde? Sie würden am Ende den Rest des Systems beschuldigen, wenn es annimmt, dass das Flag dort sein sollte oder mit einem unerwarteten Standard oder alten Wert arbeiten sollte.


2
2018-05-19 18:07



Stimme dieser Antwort voll und ganz zu. Es ist nicht von Natur aus gefährlich, aber es ist eine Gelegenheit, einen unerwarteten frühen Ausgang zu haben. - pboin
Was mich daran erinnert hat, ist ein C ++ - Profi von mir, der immer Punkte aus meinen Zuweisungen zog, weil er keinen einzigen Einstiegspunkt / einzigen Austrittspunkt in einem Programm hatte. Ich dachte, es sei ein reines "Prinzip", aber dieses Set-E-Business demonstriert definitiv, wie und warum Dinge völlig außer Kontrolle geraten können. Letztendlich geht es bei Programmen um Kontrolle und Determinismus, und bei vorzeitiger Beendigung geben Sie beide auf. - Marcin


Als ein konkreteres Beispiel für @ Marcins Antwort, die mich persönlich gebissen hat, stell dir vor, es gäbe ein rm foo/bar.txt Linie irgendwo in Ihrem Skript. Normalerweise keine große Sache, wenn foo/bar.txt existiert eigentlich nicht. Jedoch mit set -e Präsentiere jetzt dein Skript wird dort früh enden! Hoppla.


0
2018-06-22 19:00