由於訊號導致子進程異常退出,bash 不會退出

由於訊號導致子進程異常退出,bash 不會退出

我非常努力地去理解我做錯了什麼以及為什麼?

我有一個launch.sh啟動的腳本process.sh

啟動.sh

#!/bin/bash
while true; do 
./process.sh 
done

進程.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 -$!    

其中$!取得最後一個命令 (launch.sh) 的 PID,減號將訊號傳送給所有子進程,然後launch.sh繼續。為什麼?


我期望以下行為(根據此博客信號與猛擊):

後台運行腳本的 shell Alaunch.sh被中斷,Bash 等待process.sh完成。由於process.sh中的訊號處理程序導致異常回傳(退出 130)process.sh,shell A 應該退出。為什麼不呢?

如果該子進程的狀態表明它由於該訊號而異常退出,則 shell 會進行清理,刪除其訊號處理程序,並再次終止自身以觸發作業系統預設操作(異常退出)。或者,它會按照 trap 設定運行腳本的信號處理程序,然後繼續。

答案1

首先,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因未捕獲訊號而終止。由於它們是互斥的,所以 anexit 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 $$

您會看到預期的行為。

相關內容