为什么 SIGTERM 可以终止 bash,但不能终止 ash 或 dash?

为什么 SIGTERM 可以终止 bash,但不能终止 ash 或 dash?

比较bash,ashdash, 只能bash通过以下方式终止SIGTERM

kill -TERM <pid>

对于ashbash,我需要SIGHUPSIGKILL

kill -HUP <pid>
kill -KILL <pid>

这背后的原因是什么?此外,该行为似乎与系统相关:

  • bashSIGTERM在 Ubuntu 14.04 Trusty、Ubuntu 16.04 Xenial、Ubuntu 18.04 Bionic、Ubuntu 19.10 Eoan、Ubuntu 20.04 Focal、Debian 8 Jessie、Debian 9 Stretch、Debian 10 Buster、CentOS 8 上终止
  • bash不是SIGTERM在 CentOS 6、CentOS 7 上终止

答案1

仅当 bash 使用readline行编辑库并且bash等待用户输入时才会发生这种情况。

如果运行,Abash --noediting不会被杀死SIGTERM,也不会杀死自己。bashkill -TERM $$

发生这种情况是因为readline()bash 用于获取用户输入的函数将安装自己的信号处理程序SIGTERM,并在返回之前恢复原始信号处理。如果在等待用户输入SIGTERM时发生,将返回。readlinereadline()NULL

readline()调用( )的 bash 函数yy_readline_get()会将NULLreturn 解释为EOF,导致 shell 退出。场景与此非常相似回答

SIGTERM这意味着交互式 bash 也可以通过设置来生存IGNOREEOF;-):

$ bash
$ IGNOREEOF=10
$ echo $$
11096
<kill -TERM 11096 from another terminal>
$ Use "exit" to leave the shell.
<kill -TERM 11096 from another terminal>
$ Use "exit" to leave the shell.
...
<the 10th will get it>
$ exit
$

答案2

这对我来说是出乎意料的,但进行了几次构建后发现它可以在 git 的 bash 最新代码上重现,但不能在 bash 4.0 上重现。因此,这git bisect有助于确定以下提交是负责的:

% git bisect good                     
ac50fbac377e32b98d2de396f016ea81e8ee9961 is the first bad commit
commit ac50fbac377e32b98d2de396f016ea81e8ee9961
Author: Chet Ramey <[email protected]>
Date:   Wed Feb 26 09:36:43 2014 -0500

    Bash-4.3 distribution sources and documentation

Bash 的各个 git 提交往往相当大,范围也不是非常严格,但是花几分钟浏览一下该提交会发现 readline 处理 SIGTERM 的方式发生了许多变化,包括 SIGTERM 应该绕过的新 rl_signal_event_hook 以及大量新的我们检查 SIGTERM 并调用 的地方termsig_handler

这些更改的一部分与更改日志中的新条目相匹配:

Readline 在读取输入时收到信号后调用应用程序设置的事件挂钩 (rl_signal_event_hook)(read 返回 -1/EINTR,但 readline 不会立即处理该信号)以允许应用程序处理或以其他方式记录该信号。目前不调用 SIGHUP 或 SIGTERM。

从这条消息来看,我认为行为的改变可能不是故意的。

我将把这个帖子转发到 bug-bash 邮件列表,希望能弄清楚这是否是故意的。

相关内容