1

我有两个脚本。script1产生script2然后向SIGINT它​​发送一个信号。然而,script2中的陷阱似乎不起作用?!

脚本1:

#!/bin/bash
./script2 &
sleep 1
kill -SIGINT $!
sleep 2

脚本2:

#!/bin/bash
echo "~~ENTRY"
trap 'echo you hit ctrl-c, waking up...' SIGINT
sleep infinity
echo "~~EXIT"

如果更改./script2 &./script2并按下CTRL+C所有内容,则一切正常。那么我做错了什么?

4

2 回答 2

2

您的示例中有几个问题,最后我为您的问题提供了解决方案:

  • 您的第一个脚本似乎错过了一条wait语句,因此,它在大约 3 秒后退出。但是script2将保留在内存中并运行。

    您希望 bash 如何自动确定应该发送 SIGINT 信号的进程?

  • 实际上bash将在后台进程上禁用SIGINT(和SIGQUIT)并且它们无法启用(您可以通过trap单独运行命令来检查设置陷阱的当前状态)。请参阅如何从脚本发送信号 SIGINT 到脚本?重击

    所以你script2没有设置陷阱,SIGINT 因为它是一个后台进程,两者SIGINTSIGQUIT被忽略并且不能再被困或在后台进程中重置。

作为参考,以下是 bash 中与您的问题相关的文档:

进程组 id 对后台进程的影响(在文档的作业控制部分):

[...] 进程组 ID 等于当前终端进程组 ID [..] 的进程接收键盘生成的信号,例如 SIGINT。据说这些过程处于前台。 后台进程是那些进程组 ID 与终端不同的进程;这样的过程不受键盘产生的信号的影响。

SIGINT和的默认处理程序SIGQUIT(在文档的信号部分中):

bash 运行的非内置命令将信号处理程序设置为 shell 从其父级继承的值。当作业控制无效时,除了这些继承的处理程序之外,异步命令还会忽略 SIGINT 和 SIGQUIT 。

以及关于陷阱的修改(在trap内置文档中):

进入 shell 时忽略的信号不能被捕获或重置

解决方案 1

修改你script1是:

#!/bin/bash
{ ./script2; } &
sleep 1
subshell_pid=$!
pid=$(ps -ax -o ppid,pid --no-headers | sed -r 's/^ +//g;s/ +/ /g' |
                           grep "^$subshell_pid " | cut -f 2 -d " ")

kill -SIGINT $pid
sleep 2
wait      ## Don't forget this.

这是如何运作的 ?实际上,使用{and}将创建一个子shell,这将受到解释限制的限制SIGINT,因为这个子shell是一个后台进程。但是,子shell 自己的子进程是前台而不是后台进程(对于我们的子shell 范围)......因此,它们可以捕获或重置SIGINTSIGQUIT发出信号。

然后诀窍是在子shell中找到这个子ps进程的pid,在这里我用来找到唯一一个将子shell的pid作为父pid的进程。

解决方案 2

实际上,只有作为作业管理的直接新进程才会忽略其 SIGINT 和 SIGQUIT。一个简单的 bash 函数不会。因此,如果script2代码位于源自 的函数中script1,那么这将是您script1不需要其他任何内容的新代码:

#!/bin/bash
script2() {
    ## script2 code
    echo "~~ENTRY"
    trap 'echo you hit ctrl-c, waking up...' SIGINT
    sleep infinity
    echo "~~EXIT"
}
## script1 code
script2 &
sleep 1
kill -SIGINT $!
sleep 2

这也将起作用。在幕后,与解决方案 1 相同的机制正在发挥作用:bash 函数非常接近{ }构造。

于 2016-07-29T19:31:54.220 回答
0

我猜你想要实现的是,当script2接收到 SIGINT 时,它会继续并打印消息。那么,你需要

#!/bin/bash
echo "~~ENTRY"
trap 'echo you hit ctrl-c, waking up...; CONT=true' SIGINT
CONT=false
while ! $CONT
do
   sleep 1
done
echo "~~EXIT"
于 2014-08-26T17:14:44.870 回答