![为什么 bash 忽略 SIGTERM?](https://linux22.com/image/48069/%E4%B8%BA%E4%BB%80%E4%B9%88%20bash%20%E5%BF%BD%E7%95%A5%20SIGTERM%EF%BC%9F.png)
有时当我想快速注销时我就会这样做kill -15 -1
。我注意到 bash 忽略了 SIGTERM。
我想知道这种 bash 行为的理由是什么?
如果没有充分的理由就忽略 SIGTERM,这不太符合 UNIX 风格,不是吗?
更新:
对所有人都有相同(无)影响:
$ kill -TERM $$
$ type kill
kill is a shell builtin
$ command kill -TERM $$
$ /bin/kill -TERM $$
更新2:
从男人狂欢:
当 bash 是交互式的时,在没有任何陷阱的情况下,它会忽略 SIGTERM
所以这是故意的。但为什么?
答案1
首先,这不是 bash 特有的。 ATT ksh、dash 和 zsh 的行为方式相同:它们在命令行编辑期间忽略 SIGTERM 和 SIGQUIT;至于 mksh,它也不会退出,而是将它们视为 SIGINT。
ksh 手册和 bash 手册都证明在这些术语中忽略 SIGTERM 是合理的:
这样
kill 0
就不会杀死交互式 shell
kill 0
杀死所有进程进程组外壳位于 1 中。简而言之,进程组由终端前台运行的所有进程,或者后台或挂起作业的所有进程组成。
更准确地说,这就是现代 shell 中发生的情况作业控制。在这样的 shell 中,kill 0
没有用,因为 shell 将位于它自己的进程组中。较旧的 shell(或之后的现代 shell)set +m
)没有为后台命令创建进程组。因此,您可以使用该命令kill 0
来终止所有后台命令,而无需注销。² 因此,其kill 0
基本原理看起来像旧的,现在不再合理,但保留了向后兼容性。
然而,在其他类似的情况下,使外壳免疫是有用的。考虑这样一种情况:您有进程占用终端,并且您希望在不注销的情况下杀死它们。许多系统都有类似的工具pkill
它可以让你杀死终端上运行的进程。您可以运行pkill -t $TTY
或pkill -QUIT -t $TTY
终止当前终端上运行的所有进程,忽略信号的 shell 除外。
shell 通常会在用户退出它时消失(使用类似exit
或 的命令logout
),或者当其终端发出输入结束信号时(用户可以通过按Ctrl+来导致此情况D)或完全消失。在最后一种情况下,shell 收到信号 SIGHUP,并且它不会忽略该信号。
对于注销 X 会话的用例,kill -15 -1
将执行此操作,因为它会杀死导致 shell 接收 SIGHUP 的终端仿真器。事实上,杀死 X 服务器就足够了,但这需要找到它的进程 ID。如果您希望在文本会话中使用相同的命令,则可以使用kill -15 -1; exit
.无论如何,这是一个相当危险的命令。
1通常 shell 手册中似乎没有提到这一点;这是底层系统调用的一个功能。中明确提到了POSIX规范。
²如今,要做到这一点,请运行jobs -l
查看作业列表及其进程组 ID,然后kill -123 -456 …
终止进程组。
答案2
这可能会回答你的问题:
当 Bash 是交互式的时,在没有任何陷阱的情况下,它会忽略 SIGTERM(因此“kill 0”不会杀死交互式 shell),并且 SIGINT 会被捕获并处理(以便 wait 内置命令是可中断的)。当 Bash 收到 SIGINT 时,它会中断任何正在执行的循环。在所有情况下,Bash 都会忽略 SIGQUIT。如果作业控制有效(请参阅作业控制),Bash 会忽略 SIGTTIN、SIGTTOU 和 SIGTSTP。
Bash 启动的非内置命令将信号处理程序设置为 shell 从其父级继承的值。当作业控制无效时,除了这些继承的处理程序之外,异步命令还会忽略 SIGINT 和 SIGQUIT。由于命令替换而运行的命令会忽略键盘生成的作业控制信号 SIGTTIN、SIGTTOU 和 SIGTSTP。
默认情况下,shell 在收到 SIGHUP 后退出。在退出之前,交互式 shell 会向所有正在运行或已停止的作业重新发送 SIGHUP。停止的作业将被发送 SIGCONT 以确保它们收到 SIGHUP。为了防止 shell 向特定作业发送 SIGHUP 信号,应使用 disown 内置函数将其从作业表中删除(请参阅作业控制内置函数),或使用 disown -h 将其标记为不接收 SIGHUP。
如果已使用 shopt 设置了 huponexit shell 选项(请参阅 Shopt 内置),则当交互式登录 shell 退出时,Bash 会向所有作业发送 SIGHUP。
如果 Bash 正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前不会执行陷阱。当 Bash 通过 wait 内置函数等待异步命令时,接收到已设置陷阱的信号将导致 wait 内置函数立即返回,退出状态大于 128,然后立即执行陷阱。
来源:GNU Bash 手册