2013-06-21 30 views
1

以下是意外情况:在以下脚本中,SIGALRM未在预期时间调用函数alarm()SIGALRM等待子壳程序?

#!/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 +Ç

我们知道在脚本中,$$实际上表示的是OUTER进程,所以我想我们应该在1秒后看到打印到屏幕的字符串。然而,直到小孩B退出,我们才看到alarm()被调用。

当我们得到trap行的评论时,整个程序仅在1秒后终止。所以...我想SIGALRM至少已经收到,但为什么它不会调用动作?

而作为一个侧面问题,SIGALRM的默认行为是终止?从here我被告知,默认情况下它会被忽略,那么为什么OUTER在收到后会退出?

+0

这个程序的实际目标是什么? –

+0

@JohnZwinck我的实际目标是创建两个子进程并相互控制:如果第二个子进程超时,第一个子进程将发送SIGALARM到主进程来杀死第二个子进程;如果第一个孩子退出,第二个孩子会杀死第一个孩子。实际上,我已经完成了这个目标,但在这里我试图在测试过程中重现一个意想不到的情况。 – sleepsort

+0

我看你有'睡60&'..你怎么知道这不是在睡这个过程? – Bill

回答

3

bash手册页:

如果bash等待命令完成,并收到该陷阱已经设置的信号,陷阱会 不会直到命令完成执行。当bash通过内建的等待 等待异步命令时,接收到一个已设置了陷阱的信号将导致等待内建程序立即返回 ,退出状态大于128,紧接着执行陷阱。

您的原始脚本处于第一种情况。子shell(while循环)调用wait,但顶级脚本正在等待子shell,所以当它接收到信号时,陷阱不会被执行,直到子shell完成。如果您将信号发送到kill -s 14 $INNER的子shell,您将获得您期望的行为。

+0

有趣!所以它是“等待”这个坏事呢?嗯,当我通过for循环替换while循环(在代码中注释)时,我想父shell也应该被'wait'阻塞并忽略警报信号?为什么事情按预期在这个时候? – sleepsort

+0

当你使用一个for循环(我假设你的意思是'for $ in $ 0; ...'),父(即接收信号的shell)调用'wait',所以第二句适用'wait '立即返回。 –

+0

好的,非常感谢! – sleepsort