为什么`kill -s INT <zsh PID>` 与`Ctrl-C` 的行为不同?

kjo*_*kjo 4 shell kill zsh signals

从...开始:

% donothing () { echo $$; sleep 1000000 }
% donothing
47139
Run Code Online (Sandbox Code Playgroud)

如果此时我点击Ctrl-C了控制 shell 的同一个终端,那么该函数donothing确实会终止,并且我会返回命令提示符。

但是,如果相反,从不同的 shell 会话,我运行

% kill -s INT 47139
Run Code Online (Sandbox Code Playgroud)

...的donothing功能也不会终止。(同上,如果我-47139作为最后一个参数传递给kill.)

我是否需要使用与我正在使用的 PID 不同的 PID 来实现与kill -s INT我可以Ctrl-C在控制终端交互实现的相同效果?

(我主要对 的答案感兴趣zsh。)


编辑:回应吉尔斯的评论:不,我没有设置任何陷阱(尽管我有兴趣了解如何确认没有设置陷阱:有没有办法列出所有活动的陷阱?);是的,我可以用zsh -f. 事实上,我可以用我所知道的最极端的方式来复制它以获得绝对“裸” zsh(如果有更好的方法,请告诉我):

% /usr/bin/env -i /usr/bin/zsh -f
% donothing () { echo $$; sleep 1000000 }
12345
Run Code Online (Sandbox Code Playgroud)

...等等。

自从我的原始帖子以来,我在 Darwin 和 NetBSD 下都复制了上述行为,但在 Linux 下没有复制(即在 Linux 下kill -s INT <zsh PID>确实杀死了donothing上面定义的函数,而不会在进程中杀死父 shell)。

所以也许这是一个 BSD 风格的东西。更具体地说,在我尝试过的每个 Unix 中,sleep进程是进程的子zsh进程,但只有在 Linux 下SIGINT,发送到zsh进程的信号才会传播到sleep进程。

因此,为了能够donothing在 Darwin 和 NetBSD 下以非交互方式终止该函数,我需要一种方法来找到sleep-ing 孩子的 PID ,并将其发送SIGINT给它(诚然,这听起来确实很无情)。更一般地,杀死非交互方式下,达尔文和NetBSD外壳的功能,我需要递归/深度先找到后裔的的zsh过程,他们发送SIGINT给他们。

Kyl*_*nes 5

Control-c从终端向与终端关联的进程组发送中断信号,其中包括睡眠进程。通过 kill 发送 SIGINT 只会到达一个进程,在这种情况下它恰好是错误的进程,因为 $$ 返回的是 shell 的进程 ID,而不是睡眠进程。Shell 通常会忽略 SIGINT。