5

我注意到sleep当由以下人产生时不能被 SIGINT 杀死:

(sleep 1000 &)

我想知道为什么会这样。
以下所有内容都被 SIGINT 杀死:

sleep 1000
sleep 1000 &
(sleep 1000)
( ( (sleep 1000) ) )
( ( (sleep 1000)& ) )

所以我认为它必须与非交互式bash有关(进入子shell需要括号)并且任务必须在后台运行。

我编写了一个简短的 C 程序来测试该行为,发现 sa_handler 设置为 SIG_IGN - 解释现象,但为什么会这样呢?

我还没有找到任何信息是否是预期的功能(尽管考虑到手册的长度我可能只是错过了它),如果是这样,隐藏它的原因是什么。

我为感兴趣的人提供了 C 代码:

#include <stdlib.h>
#include <stdio.h>

#include <signal.h>

int main() {
    struct sigaction oldact;
    if(sigaction(SIGINT, NULL, &oldact) != 0) {
        printf("Error in sigaction\n");
        exit(1);
    }

    if(oldact.sa_flags & SA_SIGINFO) {
        printf("Using sa_sigaction\n");
    } else {
        if(oldact.sa_handler == SIG_DFL) {
            printf("Default action\n");
        } else if(oldact.sa_handler == SIG_IGN) {
            printf("Ignore signal\n");
        } else {
            printf("Other action\n");
        }
    }
    return 0;
}

编辑:

pilcrow的答案很棒,我接受了。我想补充一下为什么posix 这么说,根据signal(7) SIGINT 和 SIGQUIT 都来自 keyboard。因此,在与一个分离的进程(而不是由 bash 控制的作业)中忽略它们是有道理的。

EDIT2:

查看Mark Plotnick 评论以获得真实的解释 WHY。

4

1 回答 1

3

此构造(sleep 1000 &)将您的sleep命令放在没有作业控制的孙子外壳中:

your-shell
      \
      a compound-list in a subshell
          \
         an asynchronous list in a subshell

第一个子shell,(复合列表)(一个分组命令结构),简单地运行后台命令&(一个异步列表)然后退出。异步列表在其自己的子外壳中运行。

最终的子外壳与您的初始外壳相距太远,以至于作业控制没有意义。

根据 POSIX,“[i]f 作业控制被禁用......当 shell 执行异步列表时,列表中的命令应从 shell 继承 SIGINT 和 SIGQUIT 信号的忽略 (SIG_IGN) 信号操作。”

因此,您的睡眠在 SIGINT 设置为忽略的情况下运行。

于 2020-03-11T00:50:52.917 回答