Bash-Verhalten auf Sigterm

Bash-Verhalten auf Sigterm

Haben Sie ein Skript wie unten:

#!/bin/bash
#
# run this script.  don't run it if it's already running.
#

PIDFILE=/tmp/script.pid
LOGFILE=script.log


if [[ -f $PIDFILE ]]; then
    echo "$PIDFILE exists.  Not going to run..."
    exit 0
fi

sleep 10m >> $LOGFILE 2>&1 &
PID=$!
echo $PID > $PIDFILE

trap "echo Exiting...; rm $PIDFILE; exit $?" INT TERM EXIT KILL

wait $PID

Ich rufe dieses Skript wie folgt auf:

timeout 2m ./test_script

Bei einer Zeitüberschreitung oder Strg+C gibt das Skript zweimal „Beenden“ aus.

# timeout 2m ./test_script
^CExiting...
Exiting...
rm: cannot remove `/tmp/script.pid': No such file or directory

Unten sehen Sie die Ausgabe von strace und weitere Daten:

# ps -ef | grep -v grep | egrep -i "sleep|time"
root      8571  4690  0 12:17 pts/0    00:00:00 timeout 2m ./test_script
root      8572  8571  0 12:17 pts/0    00:00:00 /bin/bash ./test_script
root      8573  8572  0 12:17 pts/0    00:00:00 sleep 10m
# cat /tmp/script.pid
8573
# strace -p 8571
Process 8571 attached - interrupt to quit
wait4(-1, 0x7fffc43fad4c, 0, NULL)      = ? ERESTARTSYS (To be restarted)
--- SIGINT (Interrupt) @ 0 (0) ---
kill(0, SIGINT)                         = 0
kill(0, SIGCONT)                        = 0
--- SIGCONT (Continued) @ 0 (0) ---
rt_sigreturn(0)                         = 61
--- SIGINT (Interrupt) @ 0 (0) ---
rt_sigreturn(0x2)                       = 61
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 8572
--- SIGCHLD (Child exited) @ 0 (0) ---
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
Process 8571 detached

Kann mir jemand freundlicherweise dabei helfen, die internen Vorgänge zu verstehen, warum das Skript das Signal zweimal abfängt, um zweimal „Beenden …“ auszugeben?

Antwort1

Ersetzen Sie Ihre trapAnweisung durch diese drei Zeilen:

trap "echo Exiting... INT;  exit $?" INT
trap "echo Exiting... TERM; exit $?" TERM
trap "echo Exiting... EXIT; exit $?" EXIT

Sie erhalten die Ausgabe

Exiting... TERM
Exiting... EXIT

woraus wir folgern können

  • Die trap … TERMAnweisung bewirkt, dass die Shell das SIGTERM-Signal abfängt. Der timeoutBefehl sendet dem Prozess ein SIGTERM (standardmäßig), wenn das Timeout abläuft. Die Shell fängt also das Signal ab und führt den angegebenen Befehl aus, einschließlich der echo, der rm(in Ihrem eigentlichen Skript) und der exit.
  • Die trap … EXITAnweisung bewirkt, dass die Shell sich selbst eine Haftnotiz mit dem Hinweis „Denken Sie daran, dies zu tun, bevor ich nach Hause gehe“ hinterlässt. Wenn also die SIGTERM-Trap den exitBefehl ausführt, wird die EXIT-Trap ausgeführt.
  • Wenn die EXIT-Trap den exitBefehl ausführt, wird das Skript tatsächlich beendet, anstatt die EXIT-Trap auszuführen und in das Rekursionsinferno zu geraten.

Wenn Sie Ctrl+ eingeben C, während das Skript ausgeführt wird, erhalten Sie die INT-Trap, gefolgt von der EXIT-Trap. Wenn Sie das Skript ohne timeoutoder mit einer Timeout-Dauer ausführen, die länger als die Ruhezeit ist, erhalten Sie nur die EXIT-Trap.

Es ist wahrscheinlich gut genug zu sagen

trap "exit $?" INT TERM
trap "echo Exiting...; rm $PIDFILE" EXIT

Ich glaube, dass die EXIT-Trap nicht ausgeführt werden muss exit, weil Sie in die EXIT-Trap geraten, indem Sie einen exitBefehl ausführen (einschließlich des impliziten Befehls am Ende des Skripts). Wenn Sie also mit der Ausführung der EXIT-Trap ( echound rm) fertig sind, muss die Shell nichts weiter tun, als sich zu beenden. Die einzige Frage ist, mit welchem ​​Beendigungsstatus das Skript beendet wird. Und wenn Sie einen Beendigungsstatuswert speichern und ausführen rm $PIDFILE; exit $saved_status, könnte das interessant sein. Aber solange Sie von sprechen rm $PIDFILE; exit $?, wird das Skript wahrscheinlich mit dem Beendigungsstatus von beendet rm; und das wird wahrscheinlich standardmäßig passieren, wenn dies rmder letzte von Ihnen ausgeführte Befehl ist.

Ich habe ein paar schnelle Tests gemacht, die nahelegten, dass es möglich ist, die

trap "exit" INT TERM

Befehl, aber das verstehe ich nicht. Ihre Ergebnisse können abweichen.


PS: Wie Thomas sagte, trap … KILList wirkungslos.

verwandte Informationen