"Trap ... INT TERM EXIT" wirklich nötig?


63

Viele Beispiele für die trapVerwendung trap ... INT TERM EXITfür Bereinigungsaufgaben. Aber ist es wirklich notwendig, alle drei Zeichen aufzuzählen?

Das Handbuch sagt:

Wenn ein SIGNAL_SPEC EXIT (0) ist, wird ARG beim Verlassen der Shell ausgeführt.

was meines erachtens zutrifft, ob das script normal beendet wurde oder weil es empfangen wurde SIGINToder SIGTERM. Ein Experiment bestätigt auch meine Überzeugung:

$ cat ./trap-exit
#!/bin/bash
trap 'echo TRAP' EXIT
sleep 3
$ ./trap-exit & sleep 1; kill -INT %1
[1] 759
TRAP
[1]+  Interrupt               ./trap-exit
$ ./trap-exit & sleep 1; kill -TERM %1
[1] 773
TRAP
[1]+  Terminated              ./trap-exit

Warum listen dann so viele Beispiele alle auf INT TERM EXIT? Oder habe ich etwas verpasst und gibt es einen Fall, in dem eine Sohle EXITfehlen würde?


3
Denken Sie auch daran, dass bei einer Spezifikation wie z. B. INT TERM EXITder Bereinigungscode zweimal ausgeführt wird, wenn SIGTERModer SIGINTempfangen wird.
Maxschlepzig

Antworten:


19

Die POSIX-Spezifikation sagt nicht viel über die Bedingungen aus, die zur Ausführung des EXIT-Traps führen, sondern nur darüber, wie seine Umgebung bei der Ausführung aussehen muss.

In der Ascheschale von Busybox gibt Ihr Trap-Exit-Test vor dem Beenden aufgrund von SIGINT oder SIGTERM kein "TRAP" zurück. Ich würde vermuten, dass es noch andere Muscheln gibt, die möglicherweise nicht so funktionieren.

# /tmp/test.sh & sleep 1; kill -INT %1
# 
[1]+  Interrupt                  /tmp/test.sh
# 
# 
# /tmp/test.sh & sleep 1; kill -TERM %1
# 
[1]+  Terminated                 /tmp/test.sh
# 

3
dashfängt auch nicht erst an, EXITwenn es eingeht SIGINT/SIGTERM.
Maxschlepzig

4
zshauch - also vielleicht bashdie einzige Shell, in der EXITauch Signale übereinstimmen.
Maxschlepzig

@maxschlepzig zshfängt nicht an, EXITwenn es empfängt INT, aber es tut, wenn es empfängt TERM. EDIT: Ich habe gerade bemerkt, wie alt das war ...
JoL

27

Ja, da gibt es einen Unterschied.

Dieses Skript wird beendet, wenn Sie auf drücken Enteroder es senden SIGINToder SIGTERM:

trap '' EXIT
echo ' --- press ENTER to close --- '
read response

Dieses Skript wird beendet, wenn Sie Folgendes drücken Enter:

trap '' EXIT INT TERM
echo ' --- press ENTER to close --- '
read response

* Getestet in sh , Bash und Zsh . (Funktioniert nicht mehr in sh, wenn Sie einen Befehl zum Ausführen von trap hinzufügen.)


Es gibt auch das, was @Shawn gesagt hat: Ash und Dash fangen keine Signale mit ein EXIT.

Um mit Signalen robust umzugehen, ist es am besten, die Überfüllung EXITganz zu vermeiden und so etwas wie das Folgende zu verwenden:

cleanup() {
    echo "Cleaning stuff up..."
    exit
}

trap cleanup INT TERM
echo ' --- press ENTER to close --- '
read var
cleanup

1
Die Lösung mit Bereinigung macht das Richtige - sehr elegant! Es ist eine Redewendung für meine Bash-Skripte mit mktempAufrufen geworden.
Björn Dahlgren

2
Ist das exitnötig cleanup?
Jarno

3
Dies funktioniert nicht, wenn Ihr Code Shellscript-Fehler enthält, die dazu führen, dass er vorzeitig beendet wird.
10.

2
@ijw: In Bash und Ksh können Sie Traps verwenden ERR, um damit umzugehen , aber es ist nicht portabel .
Zaz

5
Diese Lösung ist nicht robust, wenn eine andere Shell sie aufruft. Wartezeiten beim kooperativen Ausstieg werden nicht verarbeitet . Sie möchten trap - INT TERM; kill -2 $$als letzte Zeile der Bereinigung der übergeordneten Shell mitteilen, dass sie vorzeitig beendet wurde. Wenn eine übergeordnete Shell foobar.sh Ihr Skript (foo.sh) und dann bar.sh aufruft, soll bar.sh nicht ausgeführt werden, wenn INT / TERM an foo.sh gesendet wird. trap cleanup EXITwird diese Weitergabe automatisch verarbeiten, daher ist es IMO das robusteste. Es bedeutet auch, dass Sie nicht cleanupam Ende des Skripts aufrufen müssen .
Nicholas Pipitone

12

Verfeinerung der letzten Antwort, da es Probleme gibt:

# Our general exit handler
cleanup() {
    err=$?
    echo "Cleaning stuff up..."
    trap '' EXIT INT TERM
    exit $err 
}
sig_cleanup() {
    trap '' EXIT # some shells will call EXIT after the INT handler
    false # sets $?
    cleanup
}
trap cleanup EXIT
trap sig_cleanup INT QUIT TERM

Punkte oben:

INT- und TERM-Handler werden beim Testen nicht beendet. Sie behandeln den Fehler, und die Shell kehrt zum Beenden zurück (was nicht allzu überraschend ist). So stelle ich sicher, dass die Bereinigung danach beendet wird und im Fall der Signale immer einen Fehlercode verwendet (und im anderen Fall eines normalen Exits den Fehlercode beibehält).

Mit bash scheint es, dass das Beenden im INT-Handler auch den EXIT-Handler aufruft. Daher entpacke ich den Exit-Handler und rufe ihn selbst auf (was in jeder Shell unabhängig vom Verhalten funktioniert).

Ich fange exit ein, weil Shell-Skripte beendet werden können, bevor sie das Ende erreichen - Syntaxfehler, set -e und eine Rückkehr ungleich Null, einfach exit aufrufen. Man kann sich nicht darauf verlassen, dass ein Muschelskript auf den Grund geht.

SIGQUIT ist Strg- \, wenn Sie es noch nie versucht haben. Erhältst du einen Bonus Coredump. Ich denke, es lohnt sich auch zu fangen, auch wenn es etwas dunkel ist.

Wenn Sie (wie ich) in der Vergangenheit immer mehrmals die Tastenkombination Strg-C drücken, wird dies manchmal in der Mitte des Bereinigungsteils Ihres Shell-Skripts angezeigt. Dies funktioniert jedoch nicht immer so perfekt, wie Sie es möchten.


2
Der Anrufer bekommen würde nur 1 als Exit - Code, unabhängig davon , welches Signal den Ausgang verursacht, während withour trapden Anrufer 130 für SIGINT, 143 für SIGTERM bekommen würde usw. Also ich würde erfassen und den richtigen Exit - Code passieren , wie: sig_cleanup() { err=$?; trap '' EXIT; (exit $err); cleanup; }.
Musiphil

2
Können Sie den Zweck trap '' EXIT INT TERMin der Bereinigungsfunktion klären ? Damit soll eine versehentliche Unterbrechung der Bereinigung durch den Benutzer verhindert werden, die Sie im letzten Absatz erwähnt haben? Ist das nicht EXITüberflüssig?
Sechs
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.