如何在没有 shell 等待当前正在运行的程序完成的情况下发送信号?

问题描述

如果我使用 kill 发送信号,它似乎要等到当前程序(在本例中为 sleep 1000)完成运行。当我通过在 shell 中按 Ctrl+C 发送 SIGINT 时,它会立即收到中断。

然而,我想要的是在通过 kill 发送信号后立即接收中断。另外,为什么当我按下 Ctrl+C 时它的行为就像我想要的那样?

#!/usr/bin/env sh
int_after_a_while() {
    local pid=$1
    sleep 2
    echo "Attempting to kill $pid with SIGINT"
    # Here I want to kill the process immediately,but it waits until sleep finishes
    kill -s INT $pid
}

trap "echo Interrupt received!" INT
int_after_a_while $$ &
sleep 1000

我将不胜感激对此问题的任何帮助。提前致谢!

解决方法

如参考答案 https://unix.stackexchange.com/questions/282525/why-did-my-trap-not-trigger/282631#282631 中所述,shell 通常会在运行陷阱之前等待实用程序完成。一些替代方案是:

  • 在后台启动长时间运行的进程,然后使用内置的 wait 等待它。当在这样的等待期间接收到捕获信号时,等待被中断并且捕获捕获。不幸的是,wait 的退出状态不能区分子进程在收到信号时退出和发生陷阱。例如
    sleep 1000 &
    p=$!
    wait "$p"
  • 通过kill -s INT 0向整个进程组发送信号。效果与用户按下 Ctrl+C 非常相似,但如果您的脚本是从另一个脚本运行的,则效果可能比您想要的更极端。
  • 使用支持 set -o trapsasync 的 shell,例如 zsh 或 FreeBSD sh,允许在等待前台作业时运行陷阱。