将交互式 shell 作为异步进程启动(信号传递)

将交互式 shell 作为异步进程启动(信号传递)

考虑这个简短的脚本。它设置了两个信号处理程序;一个用于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

我注意到的第一件事是父 shell 在子 shell 终止之前不会处理信号。我发现这是由 POSIX 记录的,所以我有责任没有正确阅读文档。

我注意到的第二件事是信号没有排队。这可能是非常基础的知识,但我却忽略了它。我假设当子进程正在执行时,生成的信号处于挂起状态,并且如果生成挂起信号再次,它被简单地忽略。

我的问题是我需要在交互式 shell(子进程)运行时将信号传递到父进程的信号处理程序。我需要这个,因为我想根据$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(在上面的跟踪输出中,看起来好像是在 shell 之前执行的,但我在脚本中按照正确的顺序执行。)

使用/bin/sh -i &没有任何改变。我做了进一步的尝试,/bin/sh -s并重定向/dev/stdin到它,以及这些的组合(-i -s),但无济于事。

所以现在我的问题是:如何从脚本启动交互式 shell 作为异步前景进程(即作为任何交互式外壳接受输入)以便其父进程可以在信号生成后立即传递信号?或者,是否可以有另一种设计?

答案1

佐藤桂的评论充分回答了我的问题:

信号是否排队取决于系统。无法保证信号按特定顺序传递。相同类型的信号可以按照它们生成的顺序传递,但这也取决于系统(在 Linux 上确实如此)。如果需要发送多种命令,请使用管道作为命令通道。

相关内容