基本信号通信

时间:2014-08-01 20:04:57

标签: bash

我有一个bash脚本,其内容是:

function foo {
    echo "Foo!"
}

function clean {
    echo "exiting"
}

trap clean EXIT 
trap foo SIGTERM

echo "Starting process with PID: $$"

while :
do
    sleep 60
done

我在终端上执行此操作:

./my_script

然后在另一个终端上执行此操作

kill -SIGTERM my_script_pid # obviously the PID is the one echoed from my_script

我希望看到消息“Foo!”从另一个终端,但它没有工作。 SIGKILL工作,EXIT代码也执行。

在终端上使用Ctrl-C my_script通常在触发器foo上运行,但不知怎的,我无法将SIGTERM信号从另一个终端发送到此终端。

用任何其他信号替换SIGTERM不会改变任何事情(除了Ctrl-C没有触发任何东西,它实际上在开始时映射到SIGUSR1。)

值得一提的是,被捕获的信号无效,任何其他信号都有默认行为。

那么,我错过了什么?有线索吗?

编辑:我刚刚检查过它不是特权问题(因为我能够发送SIGKILL,这很奇怪),但似乎并不是这样。

2 个答案:

答案 0 :(得分:4)

Bash仅在sleep返回后运行陷阱。

要理解为什么,请考虑在C / Unix内部:当信号立即发送到bash时,bash设置的相应信号处理程序只执行类似received_sigterm = true的操作。

只有当sleep返回时,并且在启动wait进程后发出的bash发出的sleep系统调用也会返回,bash将恢复其正常工作并执行陷阱(注意到{{ 1}})。

这样做是有充分理由的:直接从信号处理程序执行I / O(或通常调用内核)通常会导致未定义的行为,据我所知 - 虽然我不能告诉更多相关信息。

除了这个技术原因之外,bash还没有立即运行陷阱的另一个原因是:这实际上会破坏shell的基本语义。作业(包括管道)严格按顺序执行,除非您明确搞乱后台作业。

答案 1 :(得分:1)

您最初打印的PID是针对执行脚本的bash实例,而不是针对正在等待的sleep进程。在sleep期间,信号可能会被忽略。

如果您想查看所需的效果,请将sleep替换为像ps这样短暂的过程。

function foo {
    echo "Foo!"
}

function clean {
    echo "exiting"
}

trap clean EXIT 
trap foo SIGTERM

echo "Starting process with PID: $$"

while :
do
    ps > /dev/null
done