SIGALRM是否等待子shell进程?

SIGALRM是否等待子shell进程?,shell,signals,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 sle

以下是意外情况:在以下脚本中,
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时

我们知道在脚本中,
$$
实际上指示
外部
过程,因此我想我们应该在1秒后看到字符串打印到屏幕上。然而,直到子B退出,我们才看到调用了
alarm()

当我们对
trap
行进行注释时,整个程序仅在1秒后终止。所以我想至少收到了
SIGALRM
,但为什么它不调用操作呢


另外,作为一个附带问题,
SIGALRM
的默认行为是终止吗?从中,我被告知默认情况下会忽略它,那么为什么
OUTER
在收到它后退出?

bash
手册页:

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


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

来自
bash
手册页:

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


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

您使用此程序的实际目标是什么?@JohnZwinck我的实际目标是创建两个子进程并相互控制:如果第二个子进程超时,第一个子进程将向主进程发送sigallarm以杀死第二个子进程;如果第一个孩子退出,第二个孩子将杀死第一个孩子。实际上,我已经完成了目标,但在这里,我试图在测试期间重现一个意外情况。我看到您有
sleep 60&
。。你怎么知道这不是在休眠这个进程?@Bill抱歉,我们这里实际上有4个进程,那么你这么说是什么意思?我的意思是当你有
sleep 60&
时,当前进程(即你的shell脚本)将休眠60秒。我不知道你是怎么说睡眠会让其他脚本进入睡眠状态的。这个程序的实际目标是什么?@JohnZwinck我的实际目标是创建两个子进程并相互控制:如果第二个子进程超时,第一个子进程将向主进程发送sigallarm以杀死第二个子进程;如果第一个孩子退出,第二个孩子将杀死第一个孩子。实际上,我已经完成了目标,但在这里,我试图在测试期间重现一个意外情况。我看到您有
sleep 60&
。。你怎么知道这不是在休眠这个进程?@Bill抱歉,我们这里实际上有4个进程,那么你这么说是什么意思?我的意思是当你有
sleep 60&
时,当前进程(即你的shell脚本)将休眠60秒。我不知道你是怎么说睡眠会让其他脚本进入睡眠状态的。真有趣!所以是
等待
做了坏事?嗯,当我用for循环替换while循环(代码中的注释)时,我想父shell也应该被
wait
和ignore报警信号阻塞?为什么此时事情会按预期进行?当您使用for循环时(我假设您的意思是
for x in$0;…
),父对象(即接收信号的shell)正在调用
wait
,因此第二句话适用并且
wait
立即返回。有趣!所以是
等待
做了坏事?嗯,当我用for循环替换while循环(代码中的注释)时,我想父shell也应该被
wait
和ignore报警信号阻塞?为什么此时事情会按预期进行?当您使用for循环时(我假设您的意思是
for x in$0;…
),父对象(即接收信号的shell)正在调用
wait
,因此第二句话适用并且
wait
立即返回。