同时在Bourne shell中监视信号和进程退出

Ala*_*met 8 signals sh wait shell-trap

我有一个想要监视另一个程序的Bourne shell(/ bin/sh)脚本(为了便携性).它应该启动另一个程序,然后等待它退出.当第二个程序退出时,它会做一些最后的工作并退出.问题在于脚本需要响应信号(例如USR2)并在这些信号出现时做一些工作.

我天真的实施是:

#! /bin/sh
echo $$
trap 'echo Respond to USR2' USR2
/bin/sleep 120 &
pid=$!
wait $pid
echo $pid exited with $?
echo Doing final cleanup
Run Code Online (Sandbox Code Playgroud)

这不起作用.如果我发送shell SIGUSR2,陷阱会按预期触发,但是等待也完成,返回140./bin/sleep继续它的快乐方式.典型输出:

28849
Respond to USR2
28850 exited with 140
Doing final cleanup
Run Code Online (Sandbox Code Playgroud)

这个行为在dash和bash之间是一致的,我可以方便地访问两个Bourne shell派生物.

我目前的工作是旋转循环等待子PID消失,用kill进行探测.自旋循环似乎很浪费,并且扩大了窗口,如果PID被快速重用,我的脚本可能会错误地等待错误的进程.

#! /bin/sh
echo $$
trap 'echo Respond to USR2' USR2
/bin/sleep 15 &
pid=$!
while /bin/kill -0 $pid 2> /dev/null; do
    echo waiting...
    sleep 2
done
echo Doing final cleanup
Run Code Online (Sandbox Code Playgroud)

鉴于我的目标是同时等待另一个进程退出并能够响应信号,是否有更好的解决方案?

Wil*_*ell 3

你可以这样做:

while wait $pid; test $? -gt 128; do
    kill -0 $pid 2> /dev/null || break;
done
Run Code Online (Sandbox Code Playgroud)

但请注意 sh 标准中的以下几点:

如果 wait 的退出状态大于 128,则应用程序无法知道等待的进程是以该值退出还是被信号终止。由于大多数公用事业公司以较小的价值退出,因此很少有任何歧义。即使在不明确的情况下,大多数应用程序也只需要知道异步作业失败即可;它是否检测到错误并失败或被杀死并没有正常完成其工作并不重要。

在这种情况下,歧义略有不同。您不知道等待是否被信号中断,或者子进程是否被信号终止。