当 SIGINT 或 SIGTERM 发送到父脚本本身而不是子进程时执行命令或函数

bos*_*djo 14 scripting bash process signals shell-script

假设我有这个 script.sh

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

echo "Some other text"
#other commands here
sleep infinity
Run Code Online (Sandbox Code Playgroud)

我想在它收到或 例如时script.sh执行该函数:exit_scriptSIGINTSIGTERM

killall script.sh # it will send SIGTERM to my script
Run Code Online (Sandbox Code Playgroud)

我希望我的脚本执行这个

exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用 trap

trap exit_script SIGINT SIGTERM
Run Code Online (Sandbox Code Playgroud)

回答我问题的人证明我错了。
但它不起作用,因为trap似乎只对发送到子/子进程的信号做出反应。作为初学者,我无法破译trap的手册页,所以我可能错过了解决方案。

我猜这就是像 Chromium 这样的“真实”程序在你发送它们时所做的 SIGTERM

来自https://major.io/2010/03/18/sigterm-vs-sigkill/

一旦收到 SIGTERM,应用程序就可以确定它想要做什么。虽然大多数应用程序会清理它们的资源并停止,但有些可能不会。

zua*_*azo 16

trap对调用进程信号本身做出反应。但是你必须在接收到信号之前调用它。我的意思是,在脚本的开头。

此外,如果您想使用kill -- -$$,它也将信号发送到您的脚本,您需要在运行 kill 之前清除陷阱,否则您将以无限的kill && 陷阱循环结束。

例如:

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    trap - SIGINT SIGTERM # clear the trap
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

trap exit_script SIGINT SIGTERM

echo "Some other text"
#other commands here
sleep infinity
Run Code Online (Sandbox Code Playgroud)

正如评论中所解释的,问题在于脚本接收到信号但在处理接收到的信号之前正在等待睡眠程序结束。因此,您应该终止子进程(在本例中为睡眠进程)以运行陷阱操作。您可以使用以下内容来做到这一点:

kill -- -$(pgrep script.sh)
Run Code Online (Sandbox Code Playgroud)

或者如评论中所述:

killall -g script.sh
Run Code Online (Sandbox Code Playgroud)