我有一个调用kill 0
的脚本。我想从另一个脚本调用该脚本,并让外部脚本继续执行。 (kill 0
向调用进程的进程组中的每个进程发送一个信号,默认为SIGTERM
;请参阅man 2 kill
。)
kill0.sh
:
#!/bin/sh
kill 0
caller.sh
:
#!/bin/sh
echo BEFORE
./kill0.sh
echo AFTER
目前的行为是:
$ ./caller.sh
BEFORE
Terminated
$
如何修改caller.sh
以便在调用AFTER
后打印kill0.sh
?
修改kill0.sh
不是一种选择。假设kill0.sh
可能在调用kill 0
之前从stdin中读取并写入stdout和/或stderr,并且我不想干扰它。我仍然希望kill 0
命令杀死kill0.sh
进程本身;我也不想让它杀死来电者。
我使用的是Ubuntu 16.10 x86_64,而/bin/sh
是dash
的符号链接。这不重要,我更喜欢那些不依赖于此的答案。
这当然是更大的脚本集的简化版本,所以我有一定的XY问题风险,但我认为这里所说的问题的解决方案应该让我解决实际问题问题。 (我有一个包装器脚本,它调用指定的命令,捕获并显示其输出,以及其他一些铃声和口哨声。)
答案 0 :(得分:1)
您需要在父级中捕获信号,但在子级中启用它。所以像run-kill0.sh
这样的脚本可能是:
#!/bin/sh
echo BEFORE
trap '' TERM
(trap 15; exec ./kill0.sh)
echo AFTER
第一个trap
禁用TERM信号。在运行trap
脚本之前,子shell中的第二个kill0.sh
重新启用信号(使用信号编号而不是名称 - 见下文)。使用exec
是一个小优化 - 您可以省略它并且它将起作用。
为什么15
而不是子shell中的TERM
?因为当我使用TERM
代替15
进行测试时,我得到了:
$ sh -x run-kill0.sh
+ echo BEFORE
BEFORE
+ trap '' TERM
+ trap TERM
trap: usage: trap [-lp] [arg signal_spec ...]
+ echo AFTER
AFTER
$
当我使用15
代替TERM
(两次)时,我得到了:
$ sh -x run-kill0.sh
+ echo BEFORE
BEFORE
+ trap '' 15
+ trap 15
+ exec ./kill0.sh
Terminated: 15
+ echo AFTER
AFTER
$
使用TERM
代替第一个15
也可以。
trap
研究trap
的Bash手册显示:
trap [-lp] [arg] [sigspec …]
当shell收到信号 sigspec 时,将读取并执行 arg 中的命令。如果 arg 不存在(并且有一个 sigspec )或等于' - ',则每个指定信号的处置将重置为shell启动时的值。
第二句话是关键:trap - TERM
应该(并且凭经验确实)起作用。
#!/bin/sh
echo BEFORE
trap '' TERM
(trap - TERM; exec ./kill0.sh)
echo AFTER
运行产生:
$ sh -x run-kill0.sh
+ echo BEFORE
BEFORE
+ trap '' TERM
+ trap - TERM
+ exec ./kill0.sh
Terminated: 15
+ echo AFTER
AFTER
$
我刚刚记得为什么我使用数字而不是名字(但我的理由是shell - 当时不是Bash - 当我学习它时不识别信号名称。)
trap
然而,在Bash的辩护中,trap
的POSIX规范说:
如果第一个操作数是无符号十进制整数,则shell应将所有操作数视为条件,并将每个条件重置为默认值。否则,如果有操作数,则第一个被视为一个动作,其余被视为条件。
如果action为' - ',shell应将每个条件重置为默认值。如果action为null(“”),则shell应忽略每个指定的条件。
这比Bash文档IMO更清楚。它说明了为什么trap 15
有效。演示文稿中也有一个小故障。概要说(在一条线上):
trap n [condition...]trap [action condition...]
应该说(两行):
trap
n
[
condition
...]
trap [
action condition
...]