首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么关闭终端模拟器窗口终止使用SIGHUP陷阱的bash进程更改为不终止?

为什么关闭终端模拟器窗口终止使用SIGHUP陷阱的bash进程更改为不终止?
EN

Unix & Linux用户
提问于 2018-12-30 17:33:22
回答 3查看 1.2K关注 0票数 0

在In终端的终端模拟器窗口中的bash shell中,我运行

代码语言:javascript
运行
复制
$ trap "echo hello" SIGHUP 
$ kill -s HUP $
hello
$

然后关闭终端模拟器窗口。

关闭终端模拟器窗口只会导致SIGHUP发送到控制进程,即bash进程吗?

由于SIGHUP陷阱不会终止bash进程,所以我希望bash进程不会终止,但是为什么bash进程实际上被终止了呢?

如果我将陷阱更改为"" (忽略),也会发生同样的情况。

终端模拟器很重要。在运行在xterm窗口中的bash中,将trap设置为""将使xterm窗口不可关闭,而将trap设置为echo hello仍然可以关闭xterm窗口。

谢谢。

EN

回答 3

Unix & Linux用户

回答已采纳

发布于 2018-12-30 20:31:09

您所看到的行为是因为readline库,它正在安装自己的信号处理程序。如果您尝试以下方法:

代码语言:javascript
运行
复制
xterm -e bash --noediting

(或dashzshksh而不是bash --noediting),然后运行

代码语言:javascript
运行
复制
trap 'echo HUP' HUP

在终端中,窗口将变得不可关闭;外壳将打印HUP,就像试图关闭窗口时所期望的那样;强行关闭它(例如。使用xkill)将导致shell退出时出现EIO错误,这是完全可以预料的,因为pty已被拆除。

下面是您所观察到的行为的一个更简单的测试用例,而不涉及终端模拟器。在您的终端中运行以下命令:

代码语言:javascript
运行
复制
bash --rcfile <(echo 'trap "echo HUP" HUP')

然后kill -HUP $只打印HUP,但是(sleep 1; kill -HUP $) & (或另一个窗口中的kill -HUP )将导致shell打印exit并退出,除非您用--noediting启动它(=不要使用读行)

readline()函数(由bash调用)将在等待用户输入时安装自己的信号处理程序,并在返回时恢复原始处理程序;等待用户输入的SIGHUP将使其返回NULL,在bash (在yy_readline_get()函数中)将其视为EOF,然后才有机会运行延迟陷阱处理程序。

票数 6
EN

Unix & Linux用户

发布于 2018-12-30 18:00:51

Bash在输入不足时也会退出读取。这可以发生几种方式,常见的方法是读取shell脚本的最后一行,用户输入控件-D,或者.关闭终端窗口。

(您也可以尝试bash -i < /dev/null并注意它是如何立即退出的,因为它没有输入)。

票数 5
EN

Unix & Linux用户

发布于 2018-12-30 18:04:05

除了SIGHUP之外,还有更多的事情发生在幕后。例如,关闭终端窗口也会导致pty关闭,因此任何输出或输入都将返回I/O错误。

当您关闭窗口时,我们可以通过在strace进程上运行bash来看到这一点。

我们从bash进程开始,在提示符( pselect())处等待,然后关闭窗口.

代码语言:javascript
运行
复制
% 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。

代码语言:javascript
运行
复制
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等)。

因此,终止shell的不是最初的SIGHUP,而是pty提供输入终端的丢失。

票数 5
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/491626

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档