comportamiento de bash en sigterm

comportamiento de bash en sigterm

Tenga un guión como el siguiente:

#!/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

Estoy invocando este script de la siguiente manera:

timeout 2m ./test_script

Cuando se agota el tiempo de espera o Ctrl+c, el script imprime "Saliendo" dos veces.

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

A continuación se muestra el resultado de strace y más datos:

# 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

¿Puede alguien ayudarme a comprender los aspectos internos de por qué el script atrapa la señal dos veces para imprimir "Saliendo..." 2 veces?

Respuesta1

Si reemplaza su trapdeclaración con estas tres líneas:

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

obtendrás el resultado

Exiting... TERM
Exiting... EXIT

de donde podemos deducir

  • La trap … TERMdeclaración hace que el shell capture la señal SIGTERM. El timeoutcomando envía al proceso un SIGTERM (de forma predeterminada) cuando expira el tiempo de espera. Entonces, el shell capta la señal y ejecuta el comando especificado, incluido el echo, el rm(en su script real) y el exit.
  • La trap … EXITdeclaración hace que el caparazón deje una nota adhesiva que dice "recuerda hacer esto antes de irme a casa". Entonces, cuando la trampa SIGTERM ejecuta el exitcomando, se ejecuta la trampa EXIT.
  • Cuando la trampa EXIT ejecuta el exitcomando, el script realmente sale, en lugar de ejecutar la trampa EXIT y adentrarse en el infierno de la recursividad.

Si escribe Ctrl+ Cmientras se ejecuta el script, obtendrá la captura INT seguida de la captura EXIT. Si ejecuta el script sin timeouto con un tiempo de espera mayor que el tiempo de suspensión, solo obtendrá la captura EXIT.

Probablemente sea suficiente decir

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

Creo que no es necesario ejecutar la trampa EXIT exit, porque ingresas a la trampa EXIT ejecutando un exitcomando (incluido el implícito al final del script), por lo que, cuando termines de ejecutar la trampa EXIT ( echoy rm), al shell no le queda nada más que hacer que salir. La única pregunta es con qué estado de salida sale el script. Y, si estuviera guardando algún valor de estado de salida y haciendo rm $PIDFILE; exit $saved_status, eso podría ser interesante. Pero mientras esté hablando de rm $PIDFILE; exit $?, el script probablemente saldrá con el estado de salida de rm; y eso probablemente sucederá de forma predeterminada si rmes el último comando que ejecuta.

Hice algunas pruebas rápidas que sugirieron que es posible dejar de lado el

trap "exit" INT TERM

comando, pero no lo entiendo. YMMV.


PD: Como dijo Thomas, trap … KILLes ineficaz.

información relacionada