터미널 에뮬레이터 창을 닫으면 bash 프로세스가 종료되고 SIGHUP 트랩이 종료되지 않도록 변경되는 이유는 무엇입니까?

터미널 에뮬레이터 창을 닫으면 bash 프로세스가 종료되고 SIGHUP 트랩이 종료되지 않도록 변경되는 이유는 무엇입니까?

lxterminal 터미널 에뮬레이터 창의 bash 쉘에서 다음을 실행합니다.

$ trap "echo hello" SIGHUP 
$ kill -s HUP $$
hello
$

그런 다음 터미널 에뮬레이터 창을 닫습니다.

터미널 에뮬레이터 창을 닫으면 SIGHUP이 제어 프로세스(예: bash 프로세스)로만 전송됩니까?

SIGHUP 트랩은 bash 프로세스를 종료하지 않기 때문에 bash 프로세스가 종료되지 않을 것이라고 예상했는데 실제로 bash 프로세스가 종료된 이유는 무엇입니까?

트랩을 (무시)로 변경해도 ""같은 일이 발생합니다 .

터미널 에뮬레이터가 중요합니다. xterm 창에서 실행되는 bash에서 ""xterm 창을 닫을 수 없도록 트랩을 설정하는 동시에 echo helloxterm 창을 계속 닫도록 트랩을 설정합니다.

감사해요.

답변1

[다른 터미널 에뮬레이터의 실제적이고 가능한 동작은 무시합니다. ^D창을 닫고 pty에서 실행 중인 프로세스가 다음을 수신하도록 하는 대신 pty에 ()를 보내는 것이 완벽하게 합리적인 동작입니다. 가정VEOFWM_DELETE_WINDOWSIGHUPxterm, 이 경우 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.bashyy_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의 손실입니다.

관련 정보