考虑一下这个简短的脚本。它设置了两个信号处理程序;一个为了USR1
另一个USR2
。然后,它启动一个交互式Shell会话。
#!/bin/sh
sigusr1_handler () {
variable=1
printf "SIGUSR1: variable is now %d\n" "$variable"
}
sigusr2_handler () {
variable=2
printf "SIGUSR2: variable is now %d\n" "$variable"
}
variable=0
printf "At beginning, variable is %d\n" "$variable"
trap 'sigusr1_handler' USR1
trap 'sigusr2_handler' USR2
/bin/sh
printf "At end, variable is %d\n" "$variable"
运行它:
$ ./script.sh
At beginning, variable is 0
$ kill -s USR1 $PPID
$ kill -s USR2 $PPID
$ kill -s USR1 $PPID
$ exit
SIGUSR1: variable is now 1
SIGUSR2: variable is now 2
At end, variable is 2
我注意到的第一件事是,直到子外壳终止,父外壳才处理信号。我发现这是POSIX记录的文档,所以我因未能正确阅读文档而感到不满。
我注意到的第二件事是信号没有排队。那可能是真正的基础知识,但是它使我无法逃脱。我假设在执行子进程时,生成的信号处于暂挂状态,如果再次生成暂挂信号,则将其忽略。
我的问题是,我需要在交互式外壳程序(子进程)运行时将信号传递到父进程的信号处理程序。我之所以需要这样做,是因为我想根据$variable
子进程终止后的值来做出决定,并且如果信号的生成顺序与上述交互式会话中的顺序相同,则脚本末尾的值$variable
必须为1。
因此,我幼稚的解决方案是将子进程作为异步后台作业启动:
/bin/sh &
wait
(我知道我需要检查wait
信号传递的返回值,但稍后会进行设置。)
这是行不通的。子进程立即退出:
$ sh -x script.sh
+ variable=0
+ printf At beginning, variable is %d\n 0
At beginning, variable is 0
+ trap sigusr1_handler USR1
+ trap sigusr2_handler USR2
+ wait
+ /bin/sh
+ printf At end, variable is %d\n 0
At end, variable is 0
(wait
在上面的跟踪输出中,它看起来像是在外壳程序之前执行的,但是我在脚本中以正确的顺序执行了该操作。)
使用/bin/sh -i &
更改没有任何变化。我对其进行了进一步的尝试/bin/sh -s
并重定向/dev/stdin
到其中,以及这些(-i -s
)的组合,但均无济于事。
因此,现在我的问题是:我如何从脚本启动交互式外壳程序作为异步前台进程(即,接受输入作为任何交互式外壳程序),以便其父进程可以在生成信号后立即传递它们?或者,另一种设计可能吗?
SatōKatsura的评论充分回答了我的问题:
信号是否排队取决于系统。无法保证信号按特定顺序传递。相同类型的信号可以按照它们生成的顺序来传递,但这也与系统有关(这在Linux上是正确的)。如果您需要发送多种命令,请使用管道作为命令通道。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句