lxterminal 터미널 에뮬레이터 창의 bash 쉘에서 다음을 실행합니다.
$ trap "echo hello" SIGHUP
$ kill -s HUP $$
hello
$
그런 다음 터미널 에뮬레이터 창을 닫습니다.
터미널 에뮬레이터 창을 닫으면 SIGHUP이 제어 프로세스(예: bash 프로세스)로만 전송됩니까?
SIGHUP 트랩은 bash 프로세스를 종료하지 않기 때문에 bash 프로세스가 종료되지 않을 것이라고 예상했는데 실제로 bash 프로세스가 종료된 이유는 무엇입니까?
트랩을 (무시)로 변경해도 ""
같은 일이 발생합니다 .
터미널 에뮬레이터가 중요합니다. xterm 창에서 실행되는 bash에서 ""
xterm 창을 닫을 수 없도록 트랩을 설정하는 동시에 echo hello
xterm 창을 계속 닫도록 트랩을 설정합니다.
감사해요.
답변1
[다른 터미널 에뮬레이터의 실제적이고 가능한 동작은 무시합니다. ^D
창을 닫고 pty에서 실행 중인 프로세스가 다음을 수신하도록 하는 대신 pty에 ()를 보내는 것이 완벽하게 합리적인 동작입니다. 가정VEOF
WM_DELETE_WINDOW
SIGHUP
xterm
, 이 경우 SIGHUP
쉘의 프로세스 그룹에]를 보냅니다.
당신이 보고 있는 동작은 readline
라이브러리가 자체 신호 처리기를 설치하기 때문에 발생합니다. 다음을 시도하면:
xterm -e bash --noediting
(또는 dash
, zsh
또는 ksh
대신 bash --noediting
) 그런 다음 실행하십시오.
trap 'echo HUP' HUP
터미널에서 창을 닫을 수 없게 됩니다. HUP
창을 강제로 닫으려고 하면 쉘이 xkill
예상EIO
다음은 관찰 중인 동작에 대한 더 간단한 테스트 사례로, 터미널 에뮬레이터를 포함하지 않습니다. 터미널에서 다음 명령을 실행합니다.
bash --rcfile <(echo 'trap "echo HUP" HUP')
그러면 kill -HUP $$
그냥 print 가 됩니다 HUP
. 그러나 (sleep 1; kill -HUP $$) &
(또는 kill -HUP <pid>
다른 창에서) 다음으로 시작하지 않으면 쉘이 인쇄 exit
하고 종료 됩니다 --noediting
(= readline을 사용하지 않음).
readline()
호출된 함수는 bash
사용자 입력을 기다리는 동안 자체 신호 처리기를 설치하고, 사용자 입력을 기다리는 SIGHUP
동안 반환 시 원래 처리기를 복원합니다. 이는 return 으로 NULL
처리됩니다 EOF
.bash
yy_readline_get()
함수) 지연된 트랩 처리기를 실행할 기회를 갖기 전에.
답변2
Bash는 읽을 입력이 부족할 때도 종료됩니다. 이는 여러 가지 방법으로 발생할 수 있습니다. 일반적인 방법은 쉘 스크립트의 마지막 줄을 읽는 것, 사용자가 control-D를 입력하는 것, 터미널 창을 닫는 것 등입니다.
(이것을 시도해 보고 bash -i < /dev/null
입력이 부족하여 즉시 종료되는 것을 확인할 수도 있습니다.)
답변3
한숨 외에도 뒤에서는 많은 일이 벌어지고 있습니다. 예를 들어 터미널 창을 닫으면 pty도 닫히므로 모든 출력이나 입력은 I/O 오류를 반환합니다.
창이 닫힐 때 프로세스를 실행하면 strace
이를 확인할 수 있습니다.bash
bash
프롬프트( )에서 대기 중인 프로세스로 시작한 다음 pselect()
창을 닫습니다.
% strace -p 1090
strace: Process 1090 attached
pselect6(1, [0], NULL, NULL, NULL, {[], 8}) = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=3409, si_uid=500} ---
--- SIGCONT {si_signo=SIGCONT, si_code=SI_KERNEL} ---
rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call)
ioctl(2, TCXONC, TCOON) = -1 EIO (Input/output error)
ioctl(0, TCGETS, 0x7ffe1d1734e0) = -1 EIO (Input/output error)
ioctl(0, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig icanon echo ...}) = -1 EIO (Input/output error)
bash
핸들러를 처리하려고 하면 I/O 오류가 표시되기 시작합니다.
이 시점에서 bash는 제어 터미널이 없기 때문에 종료하기로 결정하고 모든 신호 처리기를 다시 시작하고 자신에게 또 다른 SIGHUP을 보냅니다.
rt_sigaction(SIGINT, {sa_handler=0x467410, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGTERM, {sa_handler=0x466f10, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGHUP, {sa_handler=0x4640e0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGALRM, {sa_handler=0x4676d0, sa_mask=[HUP INT ILL TRAP ABRT BUS FPE USR1 SEGV USR2 PIPE ALRM TERM XCPU XFSZ VTALRM SYS], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4bb540, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigaction(SIGWINCH, {sa_handler=0x466f00, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe5c31b3060}, {sa_handler=0x4baaa0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fe5c31b3060}, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
getpid() = 1090
kill(1090, SIGHUP) = 0
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=1090, si_uid=500} ---
그런 다음 닫기 프로세스가 계속됩니다(다시 작성 .bash_history
등).
따라서 쉘을 종료하는 것은 초기 SIGHUP이 아니라 입력 터미널을 제공하는 pty의 손실입니다.