如果 Bash 当前正在运行的子进程处理它,为什么 Bash 会忽略 SIGINT?

Dol*_*000 6 bash signals

如果我用以下命令中断它,则以下 Bash 循环将停止^C

(while true; do sleep 5; done)
Run Code Online (Sandbox Code Playgroud)

但是,以下内容不会:

(while true; do aplay test.wav; done)
Run Code Online (Sandbox Code Playgroud)

据我所知,不同之处在于aplaycatches 和 handles SIGINT,而sleep没有。

为什么是这样?POSIX 是否在某处指定了这种行为(我注意到 Dash 做了同样的事情),如果是,为什么?我不太明白为什么这种行为是可取的。事实上,Bash 怎么能区分呢?我必须承认我不知道有任何机制(至少除了ptrace/proc/黑客攻击之外)一个进程可以通过它来告诉另一个进程如何处理信号。

另外,有什么办法可以抵消吗?我注意到trap 'exit 0' SIGINT循环之前甚至没有帮助。

编辑:在子 shell 中运行循环很重要,否则父 shell 不会收到SIGINT.)

meu*_*euh 8

这个问题在这里得到了很好的解释,因为WCE 等待和合作退出,我鼓励你阅读它。基本上,您的信号被所有前台进程接收,即外壳和程序,睡眠或播放。如果不处理该信号,程序将退出并返回代码 130。shell 等待子进程结束,并看到这一点,以及它也收到信号的事实,因此退出。

当程序捕获信号时,它通常只是以代码 1 退出(与 aplay 一样)。当 shell 等待子进程时,它发现它没有因信号而结束,因此必须假设该信号是程序工作的正常方面,所以 shell 照常进行。

对于您的示例,处理 aplay 的最佳方法是检查其返回代码是否为非零并停止:

(while aplay test.wav; do :; done)
Run Code Online (Sandbox Code Playgroud)

上面提到的文章继续解释了一个想要捕获 sigint 进行一些清理的行为良好的程序,应该禁用它的处理程序,并重新杀死自己以获得正确的退出标志集。