在 shell 脚本中捕获信号时,在当前命令完成之前不会执行捕获命令。例如,考虑以下 shell 脚本:
#!/bin/bash
trap 'echo "SIGTERM caught"' SIGTERM
i=0
while : ; do
echo "$((++i))"
timeout 10 yes >/dev/null
done
如果运行此脚本,然后尝试向进程发送 SIGTERM,则陷阱函数中的 echo 语句将不会运行,直到活动命令完成为止。
通过将命令置于后台并使用等待,可以在命令执行期间处理信号,例如,
#!/bin/bash
trap 'echo "SIGTERM caught"; [[ "$pid" ]] && echo "Killing $pid" && kill "$pid"' SIGTERM
i=0
while : ; do
echo "$((++i))"
timeout 10 yes >/dev/null &
pid=$!
wait
done
然而,虽然 SIGTERM 现在被立即捕获,但这会导致进程错误地响应其他信号(如 SIGINT)。例如,如果运行上述脚本,并且 SIGTERM 早于几分钟发送,则无法通过 SIGINT 终止该脚本。例如,如果$pid
是 shell 脚本的进程 ID,则以下任一操作都会终止该进程(在后一种情况下,该进程在有机会响应 SIGTERM 之前被 SIGINT 中断):
kill -SIGINT "$pid"
kill "$pid"; kill -SIGINT "$pid"
而以下不会(进程挂起,必须通过传递 SIGKILL 来终止):
kill "$pid"; sleep 0.01; kill -SIGINT "$pid"
SIGTERM caught
# process hangs at this point
需要对陷阱进行哪些更改以避免对其他信号的不当处理?