Wenn ich trap
wie auf http://linuxcommand.org/wss0160.php#trap beschrieben verwende , um Strg-C (oder ähnliches) abzufangen und vor dem Beenden zu bereinigen, ändere ich den zurückgegebenen Exit-Code.
Jetzt wird dies in der realen Welt wahrscheinlich keinen Unterschied machen (z. B. weil die Exit-Codes nicht portierbar sind und darüber hinaus nicht immer eindeutig sind, wie unter Standard-Exit-Code beschrieben, wenn der Prozess beendet wird? ), Aber ich frage mich immer noch, ob es welche gibt Wirklich keine Möglichkeit, dies zu verhindern und stattdessen den Standardfehlercode für unterbrochene Skripte zurückzugeben?
Beispiel (in Bash, aber meine Frage sollte nicht als Bash-spezifisch angesehen werden):
#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _
Ausgabe:
$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT
EXIT
$ echo $?
1
(Bearbeitet, um es zu entfernen, um es POSIX-konformer zu machen.)
(Erneut bearbeitet, um es stattdessen zu einem Bash-Skript zu machen, ist meine Frage jedoch nicht Shell-spezifisch.)
Bearbeitet, um das tragbare "INT" für die Falle zugunsten des nicht tragbaren "SIGINT" zu verwenden.
Bearbeitet, um nutzlose geschweifte Klammern zu entfernen und mögliche Lösungen hinzuzufügen.
Aktualisieren:
Ich habe es jetzt gelöst, indem ich einfach mit einigen fest codierten Fehlercodes beendet und EXIT abgefangen habe. Dies kann auf bestimmten Systemen problematisch sein, da der Fehlercode möglicherweise abweicht oder der EXIT-Trap nicht möglich ist. In meinem Fall ist dies jedoch in Ordnung.
trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
read
, dass Sie aus dem aktuellen Coprozess lesen sollen, undtrap cmd SIGINT
funktionieren nicht, wie es der Standard vorschreibttrap cmd INT
.read -p
Eingaben aus dem aktuellen Coprozess gelesen werden.Antworten:
Sie müssen lediglich den EXIT-Handler in Ihrem Bereinigungshandler ändern . Hier ist ein Beispiel:
quelle
trap cleanup INT
statttrap cleanup EXIT
?Tatsächlich
read
scheint das Unterbrechen des internen Bashs etwas anders zu sein als das Unterbrechen eines von Bash ausgeführten Befehls. Normalerweise, wenn Sie eingebentrap
,$?
eingestellt ist und Sie können es und fahren mit dem gleichen Wert erhalten:Wenn Ihr Skript beim Ausführen eines Befehls wie
sleep
oder sogar eines eingebauten wie unterbrochen wirdwait
, werden Sie sehenund der Exit-Code ist 130. Allerdings
read -p
scheint$?
es 0 zu sein (in meiner Version von Bash 4.3.42 sowieso).Der Umgang mit Signalen während
read
kann gemäß der Änderungsdatei in meiner Version in Arbeit sein ... (/ usr / share / doc / bash / CHANGES)quelle
read
gestartet, wie in der CHANGES-Datei angegeben (zu meiner Antwort hinzugefügt). Es könnte also in Arbeit sein.128 + signo
als Exit-Code für Signale verwendet, verwendet ksh93256 + signo
. POSIX sagt: etwas über 128 ....Jeder übliche Signal-Exit-Code ist
$?
beim Eintritt in den Trap-Handler verfügbar :Wenn es einen separaten EXIT-Trap gibt, können Sie dieselbe Methode verwenden: Behalten Sie sofort den vom Signalhandler (falls vorhanden) bereinigten Exit-Status bei und geben Sie den gespeicherten Exit-Status zurück.
quelle
local
ist aber nicht POSIX.{ba,z}sh
. AFAIK, es ist das Beste, was man tun kann, unabhängig davon.$?
ist 1, unabhängig vom empfangenen Signal).Nur einen Fehlercode zurückzugeben, reicht nicht aus, um einen Exit von SIGINT zu simulieren. Ich bin überrascht, dass dies bisher niemand erwähnt hat. Weiterführende Literatur: https://www.cons.org/cracauer/sigint.html
Der richtige Weg ist:
Dies funktioniert mit Bash, Dash und zsh. Für eine weitere Portabilität müssen Sie numerische Signalspezifikationen verwenden (andererseits erwartet zsh einen Zeichenfolgenparameter für den
kill
Befehl ...).Beachten Sie auch die besondere Behandlung des
EXIT
Signals. Dies ist darauf zurückzuführen, dass einige Shells (nämlich Bash) TrapsEXIT
für jedes Signal ausführen (nach möglicherweise definierten Traps für dieses Signal). Das Zurücksetzen derEXIT
Falle verhindert dies.Code nur beim "normalen" Beenden ausführen
Die Prüfung
[ $sig = EXIT ]
ermöglicht die Ausführung von Code nur beim normalen (nicht signalisierten) Beenden. Jedoch alle haben Signale Falle haben , die bei der letzten Rücksetzen der Falle auf ,EXIT
dann;normal_exit_only_cleanup
wird auch für die Signale aufgerufen, die dies nicht tun. Es wird auch durch einen Ausgang durch ausgeführtset -e
. Dies kann behoben werden, indem Sie einfangenERR
(was von Dash nicht unterstützt wird) und[ $sig = ERR ]
vor dem eine Prüfung hinzufügenkill
.Vereinfachte Nur-Bash-Version
Auf der anderen Seite bedeutet dieses Verhalten, dass Sie in Bash einfach tun können
um nur einen Bereinigungscode auszuführen und den Exit-Status beizubehalten.
bearbeitet
Erläutern Sie Bashs Verhalten von "EXIT fängt alles ein"
Entfernen Sie das KILL-Signal, das nicht abgefangen werden kann
Entfernen Sie SIG-Präfixe aus den Signalnamen
Versuche es nicht
kill -s EXIT
set -e
Berücksichtigen Sie / ERRquelle
SIGINT
der Weg ist, um es herunterzufahren, und es kann entscheiden, mit 0 zu beenden, wenn es ohne Fehler beendet werden konnte, oder einen anderen Fehlercode, wenn es nicht sauber heruntergefahren wurde. Ein typisches Beispiel :top
. Laufen Sietop; echo $?
und drücken Sie dann Strg-C. Der Status, der auf dem Bildschirm angezeigt wird, ist 0.