Bash
如果 Bash 目前正在執行的子程序處理它,為什麼 Bash 會忽略 SIGINT?
如果我用以下命令中斷它,則以下 Bash 循環將停止
^C
:(while true; do sleep 5; done)
但是,以下內容不會:
(while true; do aplay test.wav; done)
據我所知,不同之處在於
aplay
catch 和 handleSIGINT
,而sleep
沒有。為什麼是這樣?POSIX 是否在某處指定了這種行為(我注意到 Dash 做了同樣的事情),如果是這樣,為什麼?我不太明白為什麼這種行為是可取的。事實上,Bash 怎麼能分辨出來呢?我必須承認我不知道有任何機制(至少除了
ptrace
或/proc/
黑客之外)一個程序可以告訴另一個程序如何處理信號。另外,有什麼辦法可以抵消嗎?我注意到
trap 'exit 0' SIGINT
循環之前甚至沒有幫助。(編輯:在子外殼中執行循環很重要,因為否則父外殼不會收到
SIGINT
。)
這個問題在這裡得到了很好的解釋,因為WCE 等待和合作退出,我鼓勵你閱讀它。基本上,所有前台程序(即shell 和程序、睡眠或播放)都會收到您的信號。如果程序未處理該信號,則程序以返回碼 130 退出。shell 等待子程序結束,並看到這一點,以及它也收到信號的事實,所以退出。
當程序擷取信號時,它通常只是以程式碼 1 退出(與 aplay 一樣)。當 shell 等待子程序時,它發現它沒有因為信號而結束,因此必須假設信號是程序工作的正常方面,所以 shell 正常執行。
對於您的範例,處理 aplay 的最佳方法是檢查其返回碼是否為非零並停止:
(while aplay test.wav; do :; done)
上面提到的文章繼續解釋了一個行為良好的程序想要擷取 sigint 進行一些清理,然後應該禁用它的處理程序,並重新殺死自己以獲得正確的退出標誌設置。