为什么bash会忽略SIGTERM?


10

有时,当我想快速注销时,我会这样做kill -15 -1。我注意到bash忽略了SIGTERM。

我想知道这种bash行为的原理是什么?

在没有充分理由的情况下忽略SIGTERM并不是很UNIX,不是吗?

更新:

对所有人都相同(无)的影响:

$ kill -TERM $$
$ type kill
kill is a shell builtin
$ command kill -TERM $$
$ /bin/kill -TERM $$

UPDATE2:

来自man bash

当bash是交互式的时,在没有任何陷阱的情况下,它将忽略SIGTERM

因此,它是有目的的。但为什么?


您正在使用哪种杀手?/bin/kill还是内置的外壳?如果是后者,我猜测外壳将无法使用自己的内置功能杀死自己。
terdon

@terdon:我使用了内置函数,但是我不认为这是不自行杀死它的原因。
米哈尔Šrajer

1
如果要快速注销,请使用Ctrl + d
YoMismo 2015年

1
@YoMismo: “从X会话退出”
米哈尔Šrajer

2
@MichałŠrajer:Ctrl-Alt-Backspace可以在Xorg上为我执行此操作……不过,您可能必须在xorg.conf中启用它。
Laszlo Valko 2015年

Answers:


10

首先,这并非专门针对bash。ATT ksh,dash和zsh的行为方式相同:在命令行编辑期间,它们忽略SIGTERM和SIGQUIT;至于mksh,它也不会退出,而是像SIGINT一样对待它们。

无论是ksh手册还是bash手册,在这些方面都可以忽略SIGTERM:

这样kill 0不会杀死交互式外壳

kill 0杀死外壳所在的进程组中的所有进程。简而言之,进程组由在终端上前台运行的所有进程,或在后台或挂起作业中的所有进程组成。

更确切地说,这是在具有作业控制功能的现代Shell中发生的情况。在这样的外壳中,kill 0它将没有用,因为外壳将位于其自己的进程组中。较旧的外壳(或之后的现代外壳set +m)未为后台命令创建进程组。因此,您可以使用该命令kill 0杀死所有后台命令而无需注销。²因此,其kill 0原理看起来像是一个旧的,如今不再合理,但为了向后兼容而保留。

但是,在其他类似情况下,使外壳具有免疫性也是有用的。请考虑以下情况:您有进程在占用终端,而您想杀死它们而不注销。许多系统都有类似的工具pkill,可以让您杀死在终端上运行的进程。您可以运行pkill -t $TTYpkill -QUIT -t $TTY杀死当前终端上正在运行的所有进程,但忽略信号的外壳除外。

通常,当用户退出外壳时(使用诸如exit或的命令logout),或者当外壳的终端发出输入信号结束时(用户可以通过按Ctrl+ 引起此情况),外壳就会消失D或完全消失。在最后一种情况下,shell接收到信号SIGHUP,并且它不会忽略该信号。

对于注销X会话的用例,kill -15 -1将执行此操作,因为它会杀死导致外壳程序接收SIGHUP的终端仿真器。实际上足以杀死X服务器,但这需要找到其进程ID。如果要在文本会话中使用相同的命令,可以使用kill -15 -1; exit。无论如何,这是一个非常危险的命令。

¹ 通常在shell手册中似乎没有提到这一点;这是基础系统调用的功能。它在POSIX规范中明确提到。
² 现在,要执行此操作,请运行jobs -l以查看其进程组ID的作业列表,然后kill -123 -456 …杀死进程组。


5

这可能会回答您的问题:

当Bash是交互式的时,在没有任何陷阱的情况下,它会忽略SIGTERM(这样,“ kill 0”不会杀死交互式shell),并且会捕获并处理SIGINT(这样,可中断内置的wait)。当Bash收到SIGINT时,它将脱离任何执行循环。在所有情况下,Bash都会忽略SIGQUIT。如果作业控制有效(请参阅作业控制),则Bash会忽略SIGTTIN,SIGTTOU和SIGTSTP。

由Bash启动的非内置命令将信号处理程序设置为shell从其父级继承的值。当作业控制无效时,除了这些继承的处理程序之外,异步命令还会忽略SIGINT和SIGQUIT。由于命令替换而产生的命令将忽略键盘生成的作业控制信号SIGTTIN,SIGTTOU和SIGTSTP。

默认情况下,在收到SIGHUP后,shell退出。退出之前,交互式外壳程序会将SIGHUP重新发送给所有正在运行或已停止的作业。已停止的作业将发送给SIGCONT,以确保它们收到了SIGHUP。为防止外壳程序将SIGHUP信号发送到特定作业,应使用内置的disown将其从作业表中删除(请参阅内置的Job Control),或使用disown -h将其标记为不接收SIGHUP。

如果已经用shopt设置了huponexit shell选项(请参见内置Shopt),则Bash在退出交互式登录Shell时将SIGHUP发送给所有作业。

如果Bash正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前将不执行陷阱。当Bash通过等待内置函数等待异步命令时,接收到已设置陷阱的信号将导致等待内置函数立即返回,退出状态大于128,然后立即执行陷阱。

消息来源GNU Bash手册


我在update2中引用了此内容。Man指出bash会这样做,但没有解释为什么这样做。问题仍然存在-为什么?
米哈尔Šrajer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.