Tôi đã chạy một số thử nghiệm bằng cách sử dụng CentOS 7.1 và bash. Lưu ý rằng điều này có nghĩa huponexit
là off
theo mặc định và đã bị tắt trong phần lớn các thử nghiệm của tôi.
Bạn cần nohup
khi bạn bắt đầu một công việc trong một thiết bị đầu cuối, bởi vì nếu bạn đóng thiết bị đầu cuối đó mà không thoát khỏi vỏ một cách sạch sẽ , thiết bị đầu cuối sẽ gửi tín hiệu SIGHUP đến vỏ, sau đó gửi nó cho tất cả trẻ em. Nếu bạn thoát khỏi shell một cách sạch sẽ - có nghĩa là công việc phải ở trong nền để bạn có thể nhập exit
hoặc nhấn Control-D tại dấu nhắc lệnh - không có tín hiệu nào được gửi đến công việc nền từ bash.
Kiểm tra:
Nhà ga 1
$ echo $$
16779
Nhà ga số 2
$ strace -e signal -p16779
Process 16779 attached
(đóng thiết bị đầu cuối 1, nhìn thấy trong thiết bị đầu cuối 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 +++
Công việc 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
Bắt đầu nó trong nền trong Terminal 1:
Nhà ga 1
$ ./doit.sh &
[1] 22954
Strace nó trong Terminal 2; đóng Terminal 1 sau một vài vòng lặp:
Nhà ga số 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
...
Đầu ra trong Terminal 3:
Nhà ga số 3
out 1
out 2
out 3
HUP
out 4
out 5
out 6
Tuy nhiên, nếu bạn thoát bash
, nó chỉ đơn giản là thoát mà không gửi bất kỳ tín hiệu nào cho trẻ cả. Thiết bị đầu cuối sẽ thoát vì không còn có con, nhưng tất nhiên không có ai để HUP vì vỏ con đã biến mất. Các SIGINT
, SIG_BLOCK
và SIG_SETMASK
bạn thấy dưới đây là do sleep
trong vỏ.
Nhà ga 1
$ ./doit.sh &
26275
Nhà ga số 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
Đầu 3, đầu ra
out 1
out 2
out 3
out 4
out 5
out 6
Thật thú vị, tôi đã thiết lập huponexit
để tiếp tục shopt -s huponexit; shopt
(cửa hàng sau để xem xét), sau đó thực hiện thử nghiệm cuối cùng và một lần nữa bash không gửi tín hiệu cho quá trình nền . Thậm chí THÊM xen kẽ, như chúng ta đã thấy bash đã gửi tín hiệu đến quá trình nền sau khi nó nhận được nó từ một thiết bị đầu cuối đóng vào mặt nó. Có vẻ như huponexit
có liên quan gì cách này hay cách khác.
Tôi hy vọng điều này sẽ loại bỏ bất kỳ bí ẩn hoặc sự nhầm lẫn nào liên quan đến ít nhất sự bực bội của bash, về thời điểm và cách thức tín hiệu HUP được gửi. Ít nhất các bài kiểm tra của tôi là hoàn toàn có thể tái tạo, đối với tôi. Tôi rất muốn biết liệu có bất kỳ cài đặt nào khác có thể ảnh hưởng đến hành vi của bash không.
Và, như mọi khi, YSMV (Your Shell May Vary).
Phụ lục 1
Khi tôi chạy shell như exec /bin/sh
sau đó chạy script như /bin/sh ./doit.sh &
sau đó thoát khỏi shell một cách sạch sẽ, không có tín hiệu nào được gửi đến công việc nền và nó tiếp tục chạy để hoàn thành.
Phụ lục 2
Khi tôi chạy shell như exec /bin/csh
sau đó chạy script như /bin/sh ./doit.sh &
sau đó thoát khỏi shell một cách sạch sẽ, không có tín hiệu nào được gửi đến công việc nền và nó tiếp tục chạy để hoàn thành.
--- 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