Was bedeutet der Parameter -e für die Bash-Shell-Befehlszeile?

76

Ich habe als Bash-Shell-Skript mit Header #!/bin/bash -e.

Wenn ich das Skript ausführe, wird es unterbrochen, nachdem der grepBefehl ausgeführt wurde. Wenn ich jedoch den Parameter entferne -e, kann das Skript normal ausgeführt werden. Was bedeutet Parameter -e?

Sam Ho
quelle
1
@MitchWheat Es gibt jedoch keine -eOption für Bash . Was passiert also wirklich in diesem Fall? :(
2
Es ist zwar nicht offensichtlich, aber es gibt eine -eOption für Bash: serverfault.com/questions/391255/… .
Eric O Lebigot
Nur noch ein Punkt. Wenn Sie beispielsweise Folgendes finden: [-e Dateipfad] Gibt true zurück, wenn eine Datei vorhanden ist.
Alberto Perez

Antworten:

105

Die -eOption bedeutet "Wenn eine Pipeline jemals mit einem Exit-Status ungleich Null ('Fehler') endet, beenden Sie das Skript sofort". Da grepder Exit-Status zurückgegeben wird, 1wenn keine Übereinstimmung gefunden wird, kann -edas Skript beendet werden, auch wenn kein wirklicher "Fehler" aufgetreten ist.

Wenn Sie die -eOption beibehalten möchten , aber auch einen grepBefehl haben möchten, der möglicherweise keine Übereinstimmungen findet, können Sie ihn || :an den grepBefehl anhängen . Dies bedeutet "oder, wenn der grepBefehl einen Exit-Status ungleich Null zurückgibt, run :(was nichts bewirkt)"; Der Nettoeffekt besteht also darin, -eden grepBefehl zu deaktivieren . Damit:

grep PATTERN FILE... || :

Bearbeitet hinzufügen: Der obigen Ansatz verwirft jeden Fehler: Wenn grepRückkehr , 1weil es keine Einträge gefunden, die ignoriert wird , aber auch , wenn grepRückkehr , 2weil es ein Fehler, die ignoriert wird , und wenn grepnicht in dem Weg (so Bash zurückkehrt 127), dass die ignoriert - und so weiter. Daher ist :es wahrscheinlich besser, einen Befehl zu verwenden, der den Ergebniscode überprüft und den Fehler erneut ausgibt, wenn es sich um etwas anderes handelt 1. Zum Beispiel:

grep PATTERN FILE || (( $? == 1 ))

Dies zerstört jedoch den Exit-Status. Wenn ein fehlgeschlagener Befehl ein Bash-Skript mit beendet -e, gibt das Skript normalerweise den Exit-Status des Befehls zurück. Im obigen Beispiel wird das Skript jedoch nur zurückgegeben 1. Wenn (und nur wenn) uns das interessiert, können wir es beheben, indem wir so etwas schreiben:

grep PATTERN FILE || exit_code=$?
if (( exit_code > 1 )) ; then
    exit $exit_code
fi

(erste Zeile c / o dsummersls Kommentar).

An dieser Stelle ist es wahrscheinlich am besten, eine Shell-Funktion zu erstellen, um dies für uns zu erledigen:

function grep_no_match_ok () {
    local exit_code
    grep "$@" || exit_code=$?
    return $(( exit_code == 1 ? 0 : exit_code ))
}

(Beachten Sie die Verwendung von returnanstatt von exit; wir lassen -edas Verlassen gegebenenfalls behandeln); Auf diese Weise können wir einfach schreiben:

grep_no_match_ok PATTERN FILE     # won't kill script if no matches are found

Da wir diese Funktion höchstwahrscheinlich für alle Vorkommen grepin diesem Skript verwenden möchten , können wir die Funktion tatsächlich nur benennen grep:

function grep () {
    local exit_code
    command grep "$@" || exit_code=$?
    return $(( exit_code == 1 ? 0 : exit_code ))
}

grep PATTERN FILE     # won't kill script if no matches are found

(Beachten Sie die Verwendung von command, um die Shell-Funktion in ihrem eigenen Körper zu umgehen: Wir möchten, dass die Funktion das reguläre Programm grepaufruft, anstatt unendlich zu rekursieren).

Ruakh
quelle
Sehr schön. Ich habe mich daran gemacht, Ihren Rat zu verwenden, um den Exit-Code für die spätere Verwendung zu erfassen : grep XXX FILE || exitcode=$?. Super praktisch!
dsummersl
@dsummersl: Cool, ich bin froh, dass es dir gefallen hat! Ihr Kommentar hat mich dazu inspiriert, meine Antwort um einige mögliche Verbesserungen zu erweitern, die Ihnen gefallen könnten.
Ruakh
Im Ernst, danke dafür. Das Muster, das Sie skizzieren, ist aufschlussreich. Es ist ein schönes Muster, um sich vor unerwarteten Exit-Codes zu schützen und gleichzeitig die erwarteten zu ignorieren. Ich kann definitiv sehen, wie dieses Muster verwendet wird, um den Hauptfluss meiner Skripte zu vereinfachen.
dsummersl
@ruakh Ausgezeichnete Antwort, die grep-Funktion ist wirklich nützlich. Vielen Dank.
Joe
Nur noch ein Punkt. Wenn Sie beispielsweise Folgendes finden: [-e Dateipfad] Gibt true zurück, wenn eine Datei vorhanden ist.
Alberto Perez
18

Aus dem feinen Handbuch :

Zusätzlich zu den Einzelzeichen-Shell-Befehlszeilenoptionen (siehe The Set Builtin) gibt es mehrere Optionen mit mehreren Zeichen, die Sie verwenden können.

Und wenn wir uns dann ansehen, was setzu sagen ist:

-e
Beenden Sie sofort, wenn eine Pipeline (siehe Pipelines), die aus einem einzelnen einfachen Befehl (siehe Einfache Befehle), einem in Klammern eingeschlossenen Unterschalenbefehl (siehe Befehlsgruppierung) oder einem der Befehle bestehen kann, die als Teil einer von eingeschlossenen Befehlsliste ausgeführt werden Klammern (siehe Befehlsgruppierung) geben einen Status ungleich Null zurück.

Wenn Sie also sagen bash -e, wenn ein Befehl im Skript fehlschlägt (dh einen Status ungleich Null zurückgibt), schlägt das gesamte Skript sofort fehl. Sie geben grepalso einen Wert ungleich Null zurück, da dieser nicht übereinstimmt und das gesamte Skript heruntergefahren wird, wenn Sie -ebeim Ausführen von bash angeben .

mu ist zu kurz
quelle