Die Frage steht im Titel. Was ist der Zweck eines Shell-Befehls (Teil eines Shell-Skripts), der mit einem Ausrufezeichen beginnt? Konkretes Beispiel:
In foo.sh:
#!/usr/bin/env bash
set -e
! docker stop foo
! docker rm -f foo
# ... other stuff
Ich weiß, dass ohne das Leerzeichen das Ausrufezeichen zum Ersetzen des Verlaufs verwendet wird und ! <expression>
laut Manpage verwendet werden kann, um " Wahr, wenn Ausdruck falsch ist " zu bewerten . Aber im Beispielkontext macht das für mich keinen Sinn.
$?
) 0 (Erfolg) war, wird er auf 1 umgedreht. Wenn der Rückgabecode ein Fehler war (nicht Null), wird er auf 0 (Null) umgedreht. Vielleicht wird erwartet, dass diese Befehle fehlschlagen und Sie haben-e
oder gesetztset -o errexit
? Wie auch immer, dies ist ein Fall, in dem Kommentare hätten hinzugefügt werden müssen.set -e
ignoriert Befehle, deren Exit-Status explizit mit negiert wird!
.Antworten:
TL; DR: Hiermit wird nur das
set -e
Flag in der Zeile umgangen, in der Sie es verwenden.Hinzufügen von add zu hek2mgls korrekter und nützlicher Antwort .
Du hast:
set -e ! command
Bash Referenzhandbuch → Pipelines beschreibt:
Dies bedeutet, dass das
!
Voranstellen eines Befehls dessen Beendigungsstatus negiert:$ echo 23 23 $ echo $? 0 # But $ ! echo 23 23 $ echo $? 1
Oder:
$ echo 23 && echo "true" || echo "fail" 23 true $ ! echo 23 && echo "true" || echo "fail" 23 fail
Der Exit-Status ist in vielerlei Hinsicht nützlich. In Ihrem Skript
set -e
wird das Skript zusammen mit verwendet, wenn ein Befehl einen Status ungleich Null zurückgibt.Also, wenn Sie haben:
set -e command1 command2
Wenn
command1
ein Status ungleich Null zurückgegeben wird, wird das Skript beendet und nicht fortgesetztcommand2
.Es gibt jedoch auch einen interessanten Punkt zu erwähnen, der in 4.3.1 The Set Builtin beschrieben wird :
Berücksichtigen Sie all dies, wenn Sie:
set -e ! command1 command2
Was Sie tun, ist, die
set -e
Flagge in der zu umgehencommand1
. Warum?command1
ordnungsgemäß ausgeführt wird, wird der Status Null zurückgegeben.!
wird es negieren, aberset -e
keinen Exit durch das auslösen, da es von einem mit! invertierten Rückgabestatus stammt, wie oben beschrieben.command1
fehlschlägt, wird ein Status ungleich Null zurückgegeben.!
wird es negieren, so dass die Zeile am Ende einen Nullstatus zurückgibt und das Skript normal fortgesetzt wird.quelle
set -e
bedeutet dies , dass im Skript kein Fehler zulässig ist. Mit einem führenden!
Zeichen wird jedoch eine Ausnahme markiert, was bedeutet, dass dieser Befehl in Ordnung ist.!
negiert einfach den Exit-Status eines Befehls. Dies ist nur eine der vielen Ausnahmen in der Liste der Befehle, deren Beendigungsstatusset -e
ignoriert wird.!
negiert den Exit-Status eines Befehls, unabhängig davon, ob die-e
Option aktiviert ist oder nicht . Es markiert nicht einfach einen Befehl als Ausnahme von der-e
Option.!
negiert in der Tat allein den Befehls-Exit-Status, unabhängig davon, ob erset -e
gesetzt ist oder nicht. Aber hier geht es um den Nebeneffekt von!
im Kontext vonset -e
, der das Skript nicht ausfällt, selbst wenn der Befehl erfolgreich war. Ohne solche Nebenwirkung. Das Skript schlägt fehl, wenn der Beendigungsstatus eines erfolgreichen Befehls von negiert wird!
.Wenn Sie nicht möchten, dass das Skript in beiden Fällen fehlschlägt, Fehler oder Erfolg des Befehls, können Sie auch diese Alternative verwenden:
set -e docker stop foo || true
Der boolesche Wert oder true bewirkt , dass die Pipeline immer
0
den Rückgabewert hat.quelle
man bash
sagt wenn das reservierte Wort! Vor einer Pipeline ist der Exit-Status dieser Pipeline die logische Negation des Exit-Status . Würde dies nicht bedeuten, dass der Befehl bei erfolgreicher Ausführung einen Fehler auslöst, da er ein True negiert?!
set -e\n! echo "I am okay"\n\echo "done"
läuft durch.set -e\n! give_me_an_error\n\echo "done"
läuft auch durch (dies ist, was in der Antwort beschrieben wird). Zumindest in meiner Shell (zsh unter macOS) ist es daher fehleranfällig und beeinträchtigt erfolgreicheexit 0
Befehle nicht.-e
: Die Shell wird nicht beendet, wenn (...) der Rückgabestatus des Befehls mit invertiert wird! .