这是意外情况:在以下脚本中,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
Run Code Online (Sandbox Code Playgroud)
预期:1 秒后,alarm()应调用该函数。
实际上:
alarm()一直被调用直到 60 秒,或者当我们点击Ctrl+时C。
我们知道在脚本中,$$实际上指示了该OUTER过程,所以我想我们应该在 1 秒后看到该字符串打印到屏幕上。然而,直到子 B 退出时我们才看到alarm()被调用。
当我们对该trap行进行注释时,整个程序将在 1 秒后终止。所以...我想SIGALRM至少已收到,但为什么它不调用操作?
而且,作为一个附带问题,默认行为是SIGALRM终止吗?从这里我被告知默认情况下它是被忽略的,那么为什么OUTER收到后退出呢?
从bash手册页:
如果 bash 正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前不会执行陷阱。当 bash 通过 wait 内置函数等待异步命令时,接收到已设置陷阱的信号将导致 wait 内置函数立即返回,退出状态大于 128,然后立即执行陷阱。
您的原始脚本位于第一个场景中。子shell(while read循环)已调用wait,但顶层脚本只是在等待子shell,因此当它收到信号时,陷阱不会执行,直到子shell完成。如果您使用 发送信号到子 shell kill -s 14 $INNER,您将得到您期望的行为。