Почему закрывающее окно эмулятора терминала прекращает процесс Bash с помощью ловушки SIGHUP, не заканчивается не к растущему?

Попробуйте:

sed --in-place '/PATTERN/s/.*/&;/' /path/to/file.txt
1
30.12.2018, 20:50
3 ответа

[Я буду игнорировать фактическое и возможное поведение различных эмуляторов терминала; вполне разумным поведением было бы отправить pty^D(VEOF)при закрытии окна / WM_DELETE_WINDOWвместо того, чтобы разорвать его и заставить запущенный в нем процесс получить SIGHUP; следующее предполагает xterm, что в этом случае отправит SIGHUPгруппе процессов оболочки].

Поведение, которое вы видите, связано с библиотекой readline, которая устанавливает свои собственные обработчики сигналов. Если вы попробуете следующее:

xterm -e bash --noediting

(или dash, zshили kshвместо bash --noediting), затем запустите

trap 'echo HUP' HUP

в терминале окно станет -незакрытым; оболочка просто напечатает HUP, как и ожидалось, при попытке закрыть окно; принудительно закрыть его (например. сxkill)приведет к выходу оболочки с ошибками EIO, что вполне ожидаемо, поскольку pty был разорван.

Вот более простой пример поведения, которое вы наблюдаете, без использования эмуляторов терминала. Запустите следующее в своем терминале:

bash --rcfile <(echo 'trap "echo HUP" HUP')

Затем kill -HUP $$просто напечатает HUP, но(sleep 1; kill -HUP $$) &(или kill -HUP <pid>из другого окна )заставит оболочку напечатать exitи выйти, если только вы не запустили ее с помощью--noediting(= don не использовать readline)

Функция readline(), вызываемая bash, установит свои собственные обработчики сигналов при ожидании ввода от пользователя и восстановит исходные обработчики при возвращении; a SIGHUPво время ожидания ввода от пользователя вызовет возврат NULL, который будет обработан как EOFфункциейbash(в функцииyy_readline_get()), прежде чем появится возможность запустить отложенный обработчик ловушек.

5
27.01.2020, 23:10

Bash также завершает работу, когда заканчивается ввод для чтения. Это может произойти несколькими способами, наиболее распространенными из которых являются чтение последней строки сценария оболочки, ввод пользователем control -D или... закрытие окна терминала.

(Вы также можете попробовать bash -i < /dev/nullи заметить, как он немедленно завершает работу, потому что у него закончились входные данные ).

5
27.01.2020, 23:10

Под обложкой происходит гораздо больше, чем просто SIGHUP. Например, закрытие окна терминала также приводит к закрытию pty, поэтому любой вывод или ввод будут возвращать ошибки ввода-вывода.

Мы можем увидеть это, запустив 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пытается обработать обработчик...

В этот момент обратите внимание, что 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, предоставляющего терминал для ввода.

5
27.01.2020, 23:10

Теги

Похожие вопросы