Solution 1 :
Réponse trouvée.
Pour BASH, cela dépend du huponexit
option shell, qui peut être visualisée et/ou définie à l'aide de l'élément shopt
intégré commande.
Il semble que cette option soit désactivée par défaut, du moins sur les systèmes basés sur RedHat.
Plus d'informations sur la page de manuel BASH :
Le shell se ferme par défaut à la réception d'un SIGHUP. Avant de quitter, un shell interactif renvoie le SIGHUP à tous les travaux, en cours d'exécution ou arrêtés. Les travaux arrêtés reçoivent SIGCONT pour s'assurer qu'ils reçoivent le SIGHUP. Pour empêcher le shell d'envoyer le signal à un travail particulier, il doit être supprimé de la table des travaux avec la commande intégrée disown (voir COMMANDES INTÉGRÉES DU SHELL ci-dessous) ou marqué pour ne pas recevoir SIGHUP en utilisant disown -h.
Si l'option de shell huponexit a été définie avec shopt, bash envoie un SIGHUP à toutes les tâches lorsqu'un shell de connexion interactif se termine.
Solution 2 :
Il sera envoyé SIGHUP dans mes tests :
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 à nouveau :
[[email protected]: ~] exit
zsh: you have running jobs.
[[email protected]: ~] exit
zsh: warning: 1 jobs SIGHUPed
Connection to localhost closed.
Shell2 à nouveau :
strace -e trace=signal -p1121
Process 1121 attached - interrupt to quit
pause() = ? ERESTARTNOHAND (To be restarted)
--- SIGHUP (Hangup) @ 0 (0) ---
Process 1121 detached
Pourquoi fonctionne-t-il toujours ? :
La programmation avancée dans l'environnement Unix par Stevens couvre cela dans la section 9.10 :Groupes de processus orphelins. La section la plus pertinente étant :
Étant donné que le groupe de processus est orphelin lorsque le parent se termine, POSIX.1 exige que chaque processus du groupe de processus nouvellement orphelin qui est arrêté (comme notre enfant) reçoive le signal de raccrochage (SIGHUP) suivi du signal de poursuite (SIGCONT).
Cela entraîne la poursuite de l'enfant après le traitement du signal de raccrochage. L'action par défaut pour le signal de raccrochage est de terminer le processus, nous devons donc fournir un gestionnaire de signal pour capter le signal. Nous nous attendons donc à ce que le printf dans la fonction sig_hup apparaisse avant le printf dans la fonction pr_ids.
Solution 3 :
J'ai effectué des tests avec CentOS 7.1 et bash. Notez que cela signifie huponexit
est off
par défaut, et était désactivé pour la majorité de mes tests.
Vous avez besoin de nohup
lorsque vous démarrez une tâche dans un terminal, car si vous fermez ce terminal sans quitter proprement le shell , le terminal envoie bash le signal SIGHUP au shell, qui l'envoie ensuite à tous les enfants. Si vous quittez le shell proprement, cela signifie que le travail doit déjà être en arrière-plan pour que vous puissiez taper exit
ou appuyez sur Contrôle-D à l'invite de commande - aucun signal d'aucune sorte n'est envoyé à la tâche d'arrière-plan depuis bash.
Test :
Terminal 1
$ echo $$
16779
Terminal 2
$ strace -e signal -p16779
Process 16779 attached
(fermer le terminal 1, vu dans le 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 +++
Emploi 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
Démarrez-le en arrière-plan dans le Terminal 1 :
Terminal 1
$ ./doit.sh &
[1] 22954
Tracez-le dans le Terminal 2 ; fermez le Terminal 1 après quelques boucles :
Terminal 2
$ 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
...
Sortie dans le terminal 3 :
Terminal 3
out 1
out 2
out 3
HUP
out 4
out 5
out 6
Cependant, si vous quittez bash
, il sort simplement sans envoyer aucun signal à l'enfant. Le terminal se fermera car il n'a plus d'enfant, mais bien sûr il n'y a personne pour HUP car le shell enfant est déjà parti. Le SIGINT
, SIG_BLOCK
et SIG_SETMASK
que vous voyez ci-dessous sont dus au sleep
dans le shell.
Terminal 1
$ ./doit.sh &
26275
Terminal 2
$ 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, sortie
out 1
out 2
out 3
out 4
out 5
out 6
Fait intéressant, j'ai mis huponexit
être avec shopt -s huponexit; shopt
(ce dernier doit passer en revue), puis a effectué le dernier test, et à nouveau bash n'a envoyé aucun signal au processus d'arrière-plan . Encore PLUS intéressant, comme nous l'avons vu bash l'a fait envoyer le signal au processus d'arrière-plan après l'avoir reçu d'un terminal qui s'est fermé devant lui. Il semble que huponexit
n'avait aucune incidence dans un sens ou dans l'autre.
J'espère que cela lèvera tout mystère ou confusion concernant au moins le bonheur de bash, quant au moment et à la manière dont le signal HUP est envoyé. Au moins mes tests étaient complètement reproductibles, pour moi. Je serais intéressé de savoir s'il existe d'autres paramètres susceptibles d'affecter le comportement de bash.
Et, comme toujours, YSMV (Your Shell May Vary).
Addendum 1
Lorsque j'exécute un shell en tant que exec /bin/sh
, puis exécutez le script en tant que /bin/sh ./doit.sh &
, puis quittez le shell proprement, aucun signal n'est envoyé au travail d'arrière-plan et il continue de s'exécuter jusqu'à la fin.
Addendum 2
Lorsque j'exécute un shell en tant que exec /bin/csh
, puis exécutez le script en tant que /bin/sh ./doit.sh &
, puis quittez le shell proprement, aucun signal n'est envoyé au travail d'arrière-plan et il continue de s'exécuter jusqu'à la fin.