2013-06-21 69 views
1

以下是意外情況:在以下腳本中,SIGALRM未在預期時間調用函數alarm()SIGALRM等待子殼程序?

#!/bin/sh -x 

alarm() { 
    echo "alarmed!!!" 
} 

trap alarm 14 
OUTER=$(exec sh -c 'echo $PPID') 

#for arg in `ls $0`; do 
ls $0 | while read arg; do 
    INNER=$(exec sh -c 'echo $PPID') 

    # child A, the timer 
    sleep 1 && kill -s 14 $$ & 

    # child B, some other scripts 
    sleep 60 & 

    wait $! 
done 

期望: 1秒後,函數alarm()應被調用。

其實alarm()被稱爲直到60年代,或者當我們打按Ctrl +Ç

我們知道在腳本中,$$實際上表示的是OUTER進程,所以我想我們應該在1秒後看到打印到屏幕的字符串。然而,直到小孩B退出,我們纔看到alarm()被調用。

當我們得到trap行的評論時,整個程序僅在1秒後終止。所以...我想SIGALRM至少已經收到,但爲什麼它不會調用動作?

而作爲一個側面問題,SIGALRM的默認行爲是終止?從here我被告知,默認情況下它會被忽略,那麼爲什麼OUTER在收到後會退出?

+0

這個程序的實際目標是什麼? –

+0

@JohnZwinck我的實際目標是創建兩個子進程並相互控制:如果第二個子進程超時,第一個子進程將發送SIGALARM到主進程來殺死第二個子進程;如果第一個孩子退出,第二個孩子會殺死第一個孩子。實際上,我已經完成了這個目標,但在這裏我試圖在測試過程中重現一個意想不到的情況。 – sleepsort

+0

我看你有'睡60&'..你怎麼知道這不是在睡這個過程? – Bill

回答

3

bash手冊頁:

如果bash等待命令完成,並收到該陷阱已經設置的信號,陷阱會 不會直到命令完成執行。當bash通過內建的等待 等待異步命令時,接收到一個已設置了陷阱的信號將導致等待內建程序立即返回 ,退出狀態大於128,緊接着執行陷阱。

您的原始腳本處於第一種情況。子shell(while循環)調用wait,但頂級腳本正在等待子shell,所以當它接收到信號時,陷阱不會被執行,直到子shell完成。如果您將信號發送到kill -s 14 $INNER的子shell,您將獲得您期望的行爲。

+0

有趣!所以它是「等待」這個壞事呢?嗯,當我通過for循環替換while循環(在代碼中註釋)時,我想父shell也應該被'wait'阻塞並忽略警報信號?爲什麼事情按預期在這個時候? – sleepsort

+0

當你使用一個for循環(我假設你的意思是'for $ in $ 0; ...'),父(即接收信號的shell)調用'wait',所以第二句適用'wait '立即返回。 –

+0

好的,非常感謝! – sleepsort