如果我用以下命令中断以下 Bash 循环,它就会停止^C
:
(while true; do sleep 5; done)
然而,以下情况则不然:
(while true; do aplay test.wav; done)
据我所知,区别在于aplay
catch 和 handler SIGINT
,而sleep
没有。
为什么是这样? POSIX 是否在某处指定了这种行为(我注意到 Dash 做了同样的事情),如果是,为什么?我不太明白为什么这种行为是可取的。事实上,Bash 怎样才能区分出来呢?我必须承认我不知道任何机制(至少除了ptrace
黑客/proc/
之外)一个进程可以告诉另一个进程如何处理信号。
另外,有没有办法抵消呢?我注意到即使是trap 'exit 0' SIGINT
before 循环也没有帮助。
(编辑:在子 shell 中运行循环很重要,因为否则父 shell 将不会收到SIGINT
。)
答案1
问题已经很好解释了这里, 作为世界教育理事会 等待并配合退出我鼓励你阅读它。基本上,您的信号会被所有前台进程接收,即 shell 和程序、sleep 或 aplay。如果程序不处理该信号,则退出并返回代码 130。 shell 等待子进程结束,并看到这一点,并且事实上它也收到了信号,因此退出。
当程序捕获信号时,它通常只是以代码 1 退出(与 aplay 一样)。当 shell 等待子进程时,它发现它并未因信号而结束,因此必须假设该信号是程序工作的正常方面,因此 shell 会正常运行。
对于您的示例,处理 aplay 的最佳方法是检查其返回代码是否非零并停止:
(while aplay test.wav; do :; done)
上述文章继续解释说,一个行为良好的程序想要捕获 sigint 来进行一些清理,那么应该禁用其处理程序,并重新终止自身以获得正确的退出标志设置。
答案2
在子进程完成之前,脚本不会收到信号。但是如果你在后台运行它然后等待它,父进程将要获取信号:
(while true; do aplay test.wav; done) &
wait $!
答案3
你可以试试这个,我遇到过这个问题几次,我不知道为什么它会起作用。
$(sigint)
这是为了像 bash 中的 var 一样显示结果,但要做到这一点,它必须运行它,并且有时可以工作。