4 votes

Comportement bash sur sigterm

Avoir un script comme ci-dessous:

#!/bin/bash
#
# exécuter ce script. Ne l'exécutez pas s'il est déjà en cours d'exécution.
#

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

if [[ -f $PIDFILE ]]; then
    echo "$PIDFILE existe. Ne pas exécuter..."
    exit 0
fi

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

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

wait $PID

J'invoke ce script comme ci-dessous:

timeout 2m ./test_script

En cas de délai d'attente ou de ctrl+c, le script imprime "Sortie" deux fois.

# timeout 2m ./test_script
^CSortie...
Sortie...
rm: impossible de supprimer `/tmp/script.pid': Aucun fichier ou dossier de ce type

Voici la sortie de strace et plus de données:

# 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

Est-ce que quelqu'un pourrait gentiment m'aider à comprendre pourquoi le script intercepte le signal deux fois pour imprimer "Sortie..." 2 fois ?

1voto

Si vous remplacez votre déclaration trap par ces trois lignes :

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

vous obtiendrez la sortie

Sortie... TERM
Sortie... EXIT

à partir de laquelle nous pouvons déduire

  • La déclaration trap … TERM fait en sorte que le shell attrape le signal SIGTERM.  La commande timeout envoie un signal SIGTERM au processus (par défaut) lorsque le délai d'attente expire.  Donc, le shell intercepte le signal et exécute la commande spécifiée, y compris le echo, le rm (dans votre script réel), et le exit.
  • La déclaration trap … EXIT fait en sorte que le shell se laisse un post-it disant "n'oublie pas de faire ceci avant que je m'en aille".  Ainsi, lorsque le piège SIGTERM exécute la commande exit, le piège EXIT est exécuté.
  • Lorsque le piège EXIT exécute la commande exit, le script quitte réellement, plutôt que d'exécuter le piège EXIT et de s'embarquer dans l'enfer de la récursion.

Si vous tapez Ctrl+C pendant que le script s'exécute, vous obtiendrez le piège INT suivi du piège EXIT.  Si vous exécutez le script sans timeout, ou avec une durée de temporisation plus longue que le temps de veille, vous n'obtiendrez que le piège EXIT.

Il est probablement suffisant de dire

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

Je crois que le piège EXIT n'a pas besoin d'exécuter exit, car vous entrez dans le piège EXIT en exécutant une commande exit (y compris l'implicite à la fin du script), donc, lorsque vous avez fini d'exécuter le piège EXIT (echo et rm), le shell n'a plus rien à faire que de quitter.  La seule question est avec quel statut de sortie le script quitte.  Et, si vous sauvegardiez une valeur de statut de sortie et faisiez rm $PIDFILE; exit $saved_status, cela pourrait être intéressant.  Mais tant que vous parlez de rm $PIDFILE; exit $?, le script va probablement quitter avec le statut de sortie du rm; et cela se produira probablement par défaut si le rm est la dernière commande que vous exécutez.

J'ai fait quelques tests rapides qui ont suggéré qu'il est possible de laisser de côté la

trap "exit" INT TERM

commande, mais je ne comprends pas cela.  Votre expérience peut varier.


P.S.  Comme l'a dit Thomas, trap … KILL est inefficace.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X