SIGALRM 等待子 shell 进程?

sle*_*ort 1 shell signals

这是意外情况:在以下脚本中,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收到后退出呢?

Wil*_*ell 5

bash手册页:

如果 bash 正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前不会执行陷阱。当 bash 通过 wait 内置函数等待异步命令时,接收到已设置陷阱的信号将导致 wait 内置函数立即返回,退出状态大于 128,然后立即执行陷阱。

您的原始脚本位于第一个场景中。子shell(while read循环)已调用wait,但顶层脚本只是在等待子shell,因此当它收到信号时,陷阱不会执行,直到子shell完成。如果您使用 发送信号到子 shell kill -s 14 $INNER,您将得到您期望的行为。