捕获信号而不干扰其他信号

捕获信号而不干扰其他信号

在 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

需要对陷阱进行哪些更改以避免对其他信号的不当处理?

相关内容