由于后台作业是前台作业的一个分支,因此它们具有相同的名称(trap-test.sh
); so pkill
两者都匹配并发出信号。这会以不确定的顺序杀死后台进程(留下sleep
活着,下面解释)并触发前台陷阱,因此出现竞争条件。
此外,在您链接的示例中,后台作业始终只是一个sleep x
,但在你的脚本中是sleep 10 && echo 'doing some work'
;这需要分叉的子 shell 等待sleep
终止并有条件地执行echo
。比较这两个:
$ sleep 10 &
[1] 9401
$ pstree 9401
sleep
$
$ sleep 10 && echo foo &
[2] 9410
$ pstree 9410
bash───sleep
因此,让我们从头开始并在终端中重现主要问题。
$ set +m
$ sleep 100 && echo 'doing some work' &
[1] 9923
$ pstree -pg $$
bash(9871,9871)─┬─bash(9923,9871)───sleep(9924,9871)
└─pstree(9927,9871)
$ kill $!
$ pgrep sleep
9924
$ pkill -e sleep
sleep killed (pid 9924)
我禁用了作业控制以部分模拟非交互式 shell 的行为。
杀死后台作业并没有杀死sleep
,我需要手动终止它。发生这种情况是因为发送到进程的信号不会自动广播到其目标的子进程; IE。sleep
根本没有收到TERM信号。
To kill sleep
以及子shell,我需要将后台作业放入一个单独的进程组—这需要启用作业控制,否则所有作业都会放入主 shell 的进程组中,如下所示pstree
上面的输出—,并向其发送 TERM 信号,如下所示。
$ set -m
$ sleep 100 && echo 'doing some work' &
[1] 10058
$ pstree -pg $$
bash(9871,9871)─┬─bash(10058,
10058)───sleep(10059,
10058)
└─pstree(10067,10067)
$ kill --
-$!
$
[1]+ Terminated sleep 100 && echo 'doing some work'
$ pgrep sleep
$
通过对这个概念的一些改进和调整,您的脚本如下所示:
#!/bin/bash -
set -m
usr1_handler() {
kill -- -$!
echo 'doing some work'
}
do_something() {
trap '' USR1
sleep 10 && echo 'doing some work'
}
trap usr1_handler USR1 EXIT
echo "my PID is $$"
while true; do
do_something &
wait
done
这将打印my PID is xxx
(where xxx
是前台进程的PID)并开始循环。发送 USR1 信号至xxx
(i.e kill -USR1 xxx
)将触发陷阱并导致后台进程及其子进程终止。因此wait
将返回并且循环将继续。
如果你使用pkill
相反,它无论如何都会工作,因为后台进程会忽略 USR1。
欲了解更多信息,请参阅:
-
Bash 参考手册§特殊参数 ($$ and $!) https://www.gnu.org/software/bash/manual/html_node/Special-Parameters.html#Special-Parameters,
-
POSIX kill规格 (-$! usage) https://pubs.opengroup.org/onlinepubs/9699919799/utilities/kill.html,
-
POSIX 定义 § 作业控制(如何在 POSIX shell 中实现作业控制) https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap03.html#tag_21_03_00_36,
-
Bash 参考手册 § 作业控制基础知识(作业控制在 bash 中如何工作) https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html#Job-Control-Basics,
-
POSIX Shell 命令语言§信号和错误处理 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_11,
-
POSIX wait规格 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/wait.html.