由于信号导致子进程异常退出,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 $$

您会看到预期的行为。

相关内容