由於信號,bash不會在子程序異常退出時退出
我真的很難理解我做錯了什麼,為什麼?
我有一個
launch.sh
啟動腳本process.sh
。launch.sh
#!/bin/bash while true; do ./process.sh done
process.sh
#!/bin/bash function signalHandler() { for i in {1..2}; do sleep 0.1s echo "process.sh: cleanup $i" done exit 130 } trap "signalHandler" "SIGINT" while true; do sleep 1s done
當我跑步時
./launch.sh &
然後用
kill -s SIGINT -$!
where
$!
獲取最後一個命令(launch.sh)的 PID,減號將信號發送給所有子程序,然後launch.sh
繼續。為什麼?我期望以下行為(根據此部落格Signal & Bash):
腳本
launch.sh
在後台執行的 shell A 被中斷,Bash 等到process.sh
完成。由於process.sh
中的信號處理程序導致異常返回(退出 130)process.sh
,shell A 應該退出。為什麼不呢?如果該子程序的狀態表明它由於該信號而異常退出,則 shell 會進行清理,刪除其信號處理程序,並再次殺死自身以觸發作業系統預設操作(異常退出)。或者,它執行設置為陷阱的腳本信號處理程序,然後繼續。
首先,
exit 130
不是異常退出。是正常退出,退出狀態為130。從man 3 wait
(POSIX)可以看出:If the information pointed to by stat_loc was stored by a call to waitpid() that specified the WUNTRACED and WCONTINUED flags, exactly one of the macros WIFEXITED(*stat_loc), WIFSIGNALED(*stat_loc), WIFSTOPPED(*stat_loc), and WIFCONTINUED(*stat_loc) shall evaluate to a non-zero value.
WIFEXITED
檢查正常退出,並WIFSIGNALLED
由於未擷取的信號而終止。由於這些是互斥的,exit 130
因此是正常的。當程序被 SIGINT 終止時,退出狀態為 130 是因為 bash 將其設置為程序外部的 130,因為它檢測到由於 SIGINT 導致的退出:為什麼 bash 設置 $?(退出狀態)在 Ctrl-C 或 Ctrl-Z 上非零?
其次,處理 SIGINT 然後死亡的程序應該用 SIGINT 殺死自己。Greg 的 wiki (一個很好的 shell 資源)對此有一個註釋:
如果您選擇為 SIGINT 設置處理程序(而不是使用 EXIT 陷阱),您應該知道響應 SIGINT 退出的程序應該使用 SIGINT而不是簡單地退出,以避免對其呼叫者造成問題。因此:
trap 'rm -f "$tempfile"; trap - INT; kill -INT $$' INT
現在,如果您將其更改
exit 130
為:trap - INT kill -INT $$
你會看到預期的行為。