Bash trap 命令在两个终端下的行为不同

Bash trap 命令在两个终端下的行为不同

我正在尝试在 Bash 脚本中编写信号处理程序,并在 Ubuntu 16.04 机器下进行测试。这里我使用以下命令trap

#!/bin/bash

trap "echo hi!" SIGINT SIGTERM

echo "pid is $$"
while true; do
    sleep 1;
done

运行后./test.sh,按Ctrl+会在当前终端下C立即显示消息。但是,在另一个终端下打印会延迟 1 秒。hi!kill <pid>hi!

有人能说出为什么会有这种差异吗?有没有一种方法可以无论发生什么情况都立即触发陷阱命令?(例如睡眠循环)。

答案1

谁能说出为什么会有这种差异?

Ctrl+也C能达到,而 while不能。实际上,后一种方式需要在打印之前自行退出。所谓的“1 秒延迟”最多约为 1 秒,平均约为 0.5 秒(如果操作系统忙于其他任务,则可能需要更长时间)。sleepkill <pid>sleephi!

你可以通过使用

pv -qL 1 <<< "0123456789"

代替sleep 1

注意

kill -- -<pid>    # note the minus sign before PID

会将信号发送给整个进程组,因此sleep(或pv)也是如此。


有没有一种方法,无论发生什么情况,总是立即触发陷阱命令?

有这个问题如何在同步执行期间处理 bash 中的信号?

来自其中一个答案:

如果 bash 正在等待命令完成并收到已设置陷阱的信号,直到命令完成时,陷阱才会执行. 当 bash 通过内置命令等待异步命令时wait,收到已设置陷阱的信号将导致wait内置命令立即返回,退出状态大于 128,随后立即执行陷阱。

因此,异步运行你的外部程序并使用wait。使用将其终止$!

在你的情况下,这种方法会导致以下快速和肮脏的脚本:

#!/bin/bash

trap 'kill "$!"; echo hi!' SIGINT SIGTERM

echo "pid is $$"
while true; do
    sleep 1 &
    wait
done

答案2

无需sleep 1尝试sleep 1 <&0 & wait,然后您就会发现它立即退出。

但该sleep命令仍将继续运行。

这是可行的,因为 bash 的wait命令可以被信号中断,但内部等待不能。

当然,<&0睡眠不需要这样做,但是对于以这种方式在后台运行的其他命令,除非我们故意以这种方式连接它,否则 stdin 将被断开连接。

相关内容