以下是意外情况:在以下脚本中,SIGALRM
未在预期时间调用函数alarm()
。
#!/bin/sh -x
alarm() {
echo "alarmed!!!"
}
trap alarm 14
OUTER=$(exec sh -c 'echo $PPID')
#for arg in `ls $0`; do
ls $0 | while read arg; do
INNER=$(exec sh -c 'echo $PPID')
# child A, the timer
sleep 1 && kill -s 14 $$ &
# child B, some other scripts
sleep 60 &
wait $!
done
期望:
1秒后,应调用函数alarm()
。
实际上:
调用alarm()
直到60秒,或者当我们点击 Ctrl + C 。
我们在脚本中知道,$$
实际上表示OUTER
进程,所以我想我们应该看到1秒后打印到屏幕上的字符串。但是,直到孩子B退出,我们才会看到alarm()
被调用。
当我们对trap
行进行评论时,整个程序将在1秒后终止。所以...我想至少会收到SIGALRM
,但为什么不调用行动呢?
而且,作为一个附带问题,SIGALRM
的默认行为是终止吗?从here我被告知默认情况下会被忽略,为什么OUTER
在收到后会退出?
答案 0 :(得分:3)
来自bash
手册页:
如果bash正在等待命令完成并收到已设置陷阱的信号,则陷阱将 在命令完成之前不执行。当bash通过wait等待异步命令时 内置,接收已设置陷阱的信号将导致等待内置立即返回 退出状态大于128,紧接着执行陷阱。
您的原始脚本位于第一个方案中。子shell(while读取循环)已调用wait
,但顶级脚本只是等待子shell,因此当它接收到信号时,在子shell完成之前不会执行陷阱。如果您使用kill -s 14 $INNER
将信号发送到子shell,则会得到您期望的行为。