Przeprowadziłem kilka testów przy użyciu CentOS 7.1 i bash. Uwaga: oznacza huponexit
to off
domyślnie i był wyłączony przez większość moich testów.
Potrzebujesz, nohup
kiedy zaczynasz zadanie w terminalu, ponieważ jeśli zamkniesz ten terminal bez wyjścia z powłoki , terminal wysyła bash sygnał SIGHUP do powłoki, który następnie wysyła go do wszystkich dzieci. Jeśli wyjdziesz z powłoki czysto - co oznacza, że zadanie musi już znajdować się w tle, aby można było pisać exit
lub naciskać klawisz Control-D w wierszu polecenia - z bash żadne sygnały nie będą wysyłane do zadania w tle.
Test:
Terminal 1
$ echo $$
16779
Terminal 2
$ strace -e signal -p16779
Process 16779 attached
(zamknij terminal 1, widoczny na terminalu 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 +++
Praca 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
Uruchom go w tle w Terminalu 1:
Terminal 1
$ ./doit.sh &
[1] 22954
Znajdź go w Terminalu 2; zamknij Terminal 1 po kilku pętlach:
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
...
Dane wyjściowe w terminalu 3:
Terminal 3
out 1
out 2
out 3
HUP
out 4
out 5
out 6
Jednak jeśli wyjdziesz bash
, po prostu wyjdzie, nie wysyłając żadnego sygnału do dziecka. Terminal zakończy pracę, ponieważ nie ma już potomka, ale oczywiście nie ma nikogo, kto by HUP, ponieważ skorupa potomna już nie ma. I SIGINT
, SIG_BLOCK
i SIG_SETMASK
widzisz poniżej, są spowodowanesleep
powłoką.
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
Zacisk 3, wyjście
out 1
out 2
out 3
out 4
out 5
out 6
Co ciekawe, nastawiłem huponexit
się na shopt -s huponexit; shopt
(ten ostatni test do sprawdzenia), potem wykonałem ostatni test i znowu bash nie wysłał żadnego sygnału do procesu w tle . Jeszcze bardziej interstingly, jak widzieliśmy bash zrobił wysłać sygnał do procesu w tle po otrzymaniu go od terminalu, które zostały zamknięte w jego twarz. Wygląda na to, że huponexit
nie miało to żadnego wpływu.
Mam nadzieję, że to usunie wszelką tajemnicę lub zamieszanie dotyczące przynajmniej hashingu Basha, kiedy i jak wysyłany jest sygnał HUP. Przynajmniej moje testy były dla mnie całkowicie powtarzalne. Chciałbym wiedzieć, czy są jakieś inne ustawienia, które mogą wpływać na zachowanie basha.
I, jak zawsze, YSMV (Your Shell May Vary).
Dodatek 1
Kiedy uruchamiam powłokę jako exec /bin/sh
, a następnie uruchamiam skrypt jako /bin/sh ./doit.sh &
, a następnie czysto wychodzę z powłoki, żadne sygnały nie są wysyłane do zadania w tle i kontynuuje działanie do końca.
Dodatek 2
Kiedy uruchamiam powłokę jako exec /bin/csh
, a następnie uruchamiam skrypt jako /bin/sh ./doit.sh &
, a następnie czysto wychodzę z powłoki, żadne sygnały nie są wysyłane do zadania w tle i kontynuuje działanie do końca.
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=10676, si_uid=3000090} --- rt_sigreturn() = -1 EINTR (Interrupted system call) rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0