Solución 1:
Respuesta encontrada.
Para BASH, esto depende del huponexit
opción de shell, que se puede ver y/o configurar usando el shopt
incorporado comando.
Parece que esta opción está desactivada de forma predeterminada, al menos en los sistemas basados en RedHat.
Más información en la página man de BASH:
El shell sale de forma predeterminada al recibir un SIGHUP. Antes de salir, un shell interactivo vuelve a enviar el SIGHUP a todos los trabajos, en ejecución o detenidos. Los trabajos detenidos se envían SIGCONT para asegurarse de que reciben SIGHUP. Para evitar que el shell envíe la señal a un trabajo en particular, debe eliminarse de la tabla de trabajos con el disown incorporado (ver COMANDOS INTEGRADOS DEL SHELL a continuación) o marcarlo para que no reciba SIGHUP usando disown -h.
Si la opción de shell huponexit se ha configurado con shopt, bash envía un SIGHUP a todos los trabajos cuando sale un shell de inicio de sesión interactivo.
Solución 2:
Se enviará SIGHUP en mis pruebas:
Shell1:
[[email protected]: ~] ssh localhost
[[email protected]: ~] perl -e sleep &
[1] 1121
[[email protected]: ~] ps
PID TTY TIME CMD
1034 pts/46 00:00:00 zsh
1121 pts/46 00:00:00 perl
1123 pts/46 00:00:00 ps
Shell2:
strace -e trace=signal -p1121
Shell1 de nuevo:
[[email protected]: ~] exit
zsh: you have running jobs.
[[email protected]: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.
Shell2 de nuevo :
strace -e trace=signal -p1121
Process 1121 attached - interrupt to quit
pause() = ? ERESTARTNOHAND (To be restarted)
--- SIGHUP (Hangup) @ 0 (0) ---
Process 1121 detached
¿Por qué sigue ejecutándose?:
Programación avanzada en el entorno Unix de Stevens cubre esto en la sección 9.10:Grupos de procesos huérfanos. Siendo la sección más relevante:
Dado que el grupo de procesos queda huérfano cuando el padre finaliza, POSIX.1 requiere que cada proceso del grupo de procesos recién huérfano que se detiene (como nuestro hijo) reciba la señal de colgar (SIGHUP) seguida de la señal de continuar (SIGCONT).
Esto hace que el niño continúe, después de procesar la señal de colgar. La acción predeterminada para la señal de colgar es finalizar el proceso, por lo que debemos proporcionar un controlador de señal para captar la señal. Por lo tanto, esperamos que printf en la función sig_hup aparezca antes que printf en la función pr_ids.
Solución 3:
Realicé algunas pruebas con CentOS 7.1 y bash. Tenga en cuenta que esto significa huponexit
es off
de forma predeterminada, y estaba desactivado para la mayoría de mis pruebas.
Necesitas nohup
cuando inicia un trabajo en una terminal, porque si cierra esa terminal sin salir del shell limpiamente , la terminal envía a bash la señal SIGHUP al shell, que luego la envía a todos los niños. Si sale del shell limpiamente, lo que significa que el trabajo ya debe estar en segundo plano para que pueda escribir exit
o presione Control-D en el símbolo del sistema; no se envían señales de ningún tipo al trabajo en segundo plano desde bash.
Prueba:
$ echo $$
16779
$ strace -e signal -p16779
Process 16779 attached
(cerrar terminal 1, visto en terminal 2):
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16777, si_uid=3000090} ---
rt_sigprocmask(SIG_BLOCK, [CHLD TSTP TTIN TTOU], [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], 8) = 0
rt_sigprocmask(SIG_SETMASK, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], NULL, 8) = 0
rt_sigaction(SIGHUP, {SIG_DFL, [], SA_RESTORER, 0x7f7ace3d9a00}, {0x456880, [HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], SA_RESTORER, 0x7f7ace3d9a00}, 8) = 0
kill(16779, SIGHUP) = 0
rt_sigreturn() = -1 EINTR (Interrupted system call)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=16779, si_uid=3000090} ---
+++ killed by SIGHUP +++
Trabajo doit.sh
:
#!/bin/bash
imhupped() {
echo "HUP" >> /tmp/outfile
}
trap imhupped SIGHUP
for i in $(seq 1 6); do echo out $i >> /tmp/outfile; sleep 5; done
Inícielo en segundo plano en la Terminal 1:
$ ./doit.sh &
[1] 22954
Búscalo en la Terminal 2; cierre la Terminal 1 después de un par de bucles:
$ strace -e signal -p22954
Process 22954 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=22980, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn() = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f7a5d547a00}, {0x43e4b0, [], SA_RESTORER, 0x7f7a5d547a00}, 8) = 0
...
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=21685, si_uid=3000090} ---
rt_sigreturn() = -1 EINTR (Interrupted system call)
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=23017, si_status=SIGHUP, si_utime=0, si_stime=0} ---
rt_sigreturn() = 0
...
Salida en Terminal 3:
out 1
out 2
out 3
HUP
out 4
out 5
out 6
Sin embargo, si sale de bash
, simplemente sale sin enviar ninguna señal al niño. La terminal se cerrará porque ya no tiene un elemento secundario, pero, por supuesto, no hay nadie para HUP porque el shell secundario ya no está. El SIGINT
, SIG_BLOCK
y SIG_SETMASK
que ves a continuación se deben al sleep
en la concha.
$ ./doit.sh &
26275
$ strace -e signal -p26275
Process 26275 attached
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26280, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn() = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
(..."exit" is typed in bash, notice no new signals sent...)
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26303, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn() = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [INT CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGINT, {0x43e4b0, [], SA_RESTORER, 0x7f5edd3a5a00}, {SIG_DFL, [], SA_RESTORER, 0x7f5edd3a5a00}, 8) = 0
Terminal 3, salida
out 1
out 2
out 3
out 4
out 5
out 6
Curiosamente, configuré huponexit
estar con shopt -s huponexit; shopt
(este último compró para revisar), luego realizó la última prueba y nuevamente bash no envió ninguna señal al proceso en segundo plano . Aún MÁS interesante, como hemos visto, bash did enviar la señal al proceso de fondo después de que la recibió de una terminal que se cerró en su cara. Parece que huponexit
no tenía relación en un sentido ni en el otro.
Espero que esto elimine cualquier misterio o confusión con respecto al menos a la felicidad de bash, sobre cuándo y cómo se envía la señal HUP. Al menos mis pruebas fueron completamente reproducibles, para mí. Me interesaría saber si hay alguna otra configuración que pueda estar afectando el comportamiento de bash.
Y, como siempre, YSMV (Your Shell May Vary).
Anexo 1
Cuando ejecuto un shell como exec /bin/sh
, luego ejecute el script como /bin/sh ./doit.sh &
, luego salga del shell limpiamente, no se envían señales al trabajo en segundo plano y continúa ejecutándose hasta completarse.
Anexo 2
Cuando ejecuto un shell como exec /bin/csh
, luego ejecute el script como /bin/sh ./doit.sh &
, luego salga del shell limpiamente, no se envían señales al trabajo en segundo plano y continúa ejecutándose hasta completarse.