Muchos ejemplos para trapusar trap ... INT TERM EXITen tareas de limpieza. Pero, ¿es realmente necesario enumerar las tres sigspecs?
El manual dice:
Si un SIGNAL_SPEC es EXIT (0) ARG se ejecuta al salir del shell.
lo cual creo que se aplica si el script terminó normalmente o si terminó porque recibió SIGINTo SIGTERM. Un experimento también confirma mi creencia:
$ 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
Entonces, ¿por qué tantos ejemplos enumeran todo INT TERM EXIT? ¿O me perdí algo y hay algún caso en el EXITque faltaría una suela ?

INT TERM EXITel código de limpieza se ejecuta dos veces cuandoSIGTERMoSIGINTse recibe.Respuestas:
La especificación POSIX no dice mucho sobre las condiciones que resultan en la ejecución de la trampa EXIT, solo sobre cómo debe verse su entorno cuando se ejecuta.
En el caparazón de cenizas de Busybox, su prueba de salida de trampa no hace eco 'TRAP' antes de salir debido a SIGINT o SIGTERM. Sospecho que existen otros proyectiles que pueden no funcionar de esa manera.
fuente
dashTampoco se atrapa justoEXITcuando recibeSIGINT/SIGTERM.zshtambién, por lo tanto, tal vezbashsea el único shell dondeEXITtambién coinciden las señales.zshno se atrapaEXITcuando recibeINT, pero lo hace cuando recibeTERM. EDITAR: Acabo de notar cuántos años tenía esto ...Sí, hay una diferencia.
Este script saldrá cuando lo presione Enter, o lo envíe
SIGINToSIGTERM:Este script saldrá cuando presione Enter:
* Probado en sh , Bash y Zsh . (ya no funciona en sh cuando agrega un comando para que se ejecute trap)
También está lo que dijo @Shawn: Ash y Dash no atrapan las señales
EXIT.Entonces, para manejar las señales de manera robusta, es mejor evitar las trampas por
EXITcompleto y usar algo como esto:fuente
mktempllamadas.exitnecesario encleanup?ERRpara manejar eso, pero no es portátil .trap - INT TERM; kill -2 $$como última línea de limpieza, decirle al shell principal que salió prematuramente. Si un shell primario foobar.sh llama a su script (foo.sh), y luego llama a bar.sh, no desea que bar.sh se ejecute si se envía INT / TERM a su foo.sh.trap cleanup EXITmanejará esta propagación automáticamente, por lo que es IMO la más robusta. También significa que no tendría que llamarcleanupal final del guión.Refinando la última respuesta, porque tiene problemas:
Puntos anteriores:
Los controladores INT y TERM no se dan por vencidos cuando pruebo: manejan el error y el shell vuelve a salir (y esto no es demasiado sorprendente). Por lo tanto, me aseguro de que la limpieza salga después, y en el caso de las señales siempre usa un código de error (y en el otro caso de una salida normal, conserva el código de error).
Con bash, parece que salir en el controlador INT también llama al controlador EXIT, por lo tanto, destapo el controlador de salida y lo llamo yo mismo (que funcionará en cualquier shell independientemente del comportamiento).
Atrapo la salida porque los scripts de shell pueden salir antes de llegar al fondo: errores de sintaxis, set -e y un retorno distinto de cero, simplemente llamando a exit. No puede confiar en que un shellscript llegue al fondo.
SIGQUIT es Ctrl- \ si nunca lo has probado. Obtiene un coredump adicional. Así que creo que también vale la pena atraparlo, incluso si es un poco oscuro.
La experiencia pasada dice que si (como yo) siempre presiona Ctrl-C varias veces, a veces lo atrapará a la mitad de la parte de limpieza de su script de shell, por lo que esto funciona, pero no siempre tan perfectamente como le gustaría.
fuente
trapla persona que llama obtendría 130 para SIGINT, 143 para SIGTERM, etc. Así que me gustaría capturar y transmitir el código de salida correcto como:sig_cleanup() { err=$?; trap '' EXIT; (exit $err); cleanup; }.trap '' EXIT INT TERMla función de limpieza? ¿Es esto para evitar que el usuario interrumpa accidentalmente la limpieza que mencionó en el último párrafo? ¿No esEXITredundante?