1

这是意外情况:在以下脚本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是终止吗?从这里我被告知默认情况下它被忽略,那么为什么OUTER在收到它后退出呢?

4

1 回答 1

4

bash手册页:

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

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

于 2013-06-21T12:41:15.980 回答