无法在 bash 中中断外部信号

Unable to trup external signal in bash

我正在尝试使用常规系统 sleep 编写一个脚本,该脚本将大部分保持空闲状态等待预定义的时间。当我尝试从外部杀死它时(例如 start-stop-daemon ),问题就出现了。主进程会被杀死,但是子进程会一直留在系统中,直到 运行 出来。我决定制造一个理智陷阱并从脚本本身杀死活动 sleep。这是如何完成的:

cleanup()
{
        local PIDS=$(jobs -p)
        echo $PIDS
        [ -n "$PIDS" ] && kill $PIDS
        exit 0
}
trap "cleanup" SIGINT SIGTERM

sleep 1h

当我在脚本处于前台时按 Ctrl-C(发送 SIGINT)时,cleanup() 过程将启动,但如果我试图杀死(发送默认 SIGTERM)运行来自其他控制台的 ning 脚本没有任何反应。没有执行 cleanup(),两个脚本都没有终止。该脚本将继续 运行 就像什么也没发生一样。 任何人都可以解释发生了什么以及如何捕获外部 SIGTERM 并执行所需的过程吗?

Philippe mentions in a comment above, the Bash Reference Manual § 3.7.6 "Signals" 部分所述:

If Bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.

SIGINT 和 SIGTERM 实际上都是如此;您的方法似乎适用于 Ctrl-C 的原因是 Ctrl-C 将 SIGINT 发送到前台进程组中的 每个 进程,包括 sleep 进程,所以 sleep 立即退出,然后其父脚本退出。

我刚刚引用的段落的其余部分提供了解决此问题的最明确方法:

When Bash is waiting for an asynchronous command via the wait builtin, the reception of a signal for which a trap has been set will cause the wait builtin to return immediately with an exit status greater than 128, immediately after which the trap is executed.

换句话说,您可以将 sleep 1h 替换为 sleep 1h & wait(其中 sleep 1h &wait 可以在不同的行或在同一行,如您所愿) 立即调用您的陷阱(因此它可以终止 sleep 进程)。

或者,您可以删除 trap 设置并用脚本退出后不会继续 运行 的内容替换 sleep 1h;例如:

  • 循环只是短暂地(例如 sleep 1s)重复休眠,直到一个小时过去。
  • read -t 3600,最多等待 3600 秒(一小时)让文本出现在标准输入上。 (N.B。这种方法只有在标准输入上实际上没有任何文本时才有效。)

(这些依赖于循环(在前一种情况下)或 read 调用(在后一种情况下)是 Bash 进程本身的一部分,而不是分叉的子进程。)