我正在尝试从 bash 脚本启动几个子程序,然后等待任何一个在退出另一个并退出脚本之前先退出其中一个。
CMD1PID= CMD2PID= 退出陷阱(){ echo“退出陷阱:杀死工作......” sudo 杀死 $CMD1PID $CMD2PID 出口 } 设置-bm 陷阱 exit_trap 退出 INT 术语 sudo cmd1 --args & CMD1PID=$? sudo cmd2 --args & CMD2PID=$? 等待 $CMD1PID $CMD2PID
(作为参考,这是GNU bash, version 4.2.37(1)-release (arm-unknown-linux-gnueabi)
在 Debian Weezy 上)
不幸的是,这似乎不能正常工作。我尝试了几种变体,例如:
- 在命令周围使用大括号,然后显式终止 shell 进程,即
{ cmd1 --args ; kill -USR1 $$ ; } &
或类似的,然后捕获 USR1 - 用于
kill 0
在退出时终止仍在运行的命令 - 陷阱- 这样做的缺点是,如果需要,
CHLD
我无法在命令之间切换,而我最终可能需要这样做。sleep
...但我经常遇到的问题是:
- 终止其中一个命令不会导致父 Bash 进程退出和/或终止另一个命令
- 终止父 Bash 进程不会导致两个命令都被终止
我怀疑也许我对使用 sudo 的要求让我绊倒了,因为其他脚本中的其他人似乎在类似的脚本上运气很好。有没有一种好方法可以完成我在 bash 中尝试做的事情?
答案1
您有两个问题:您需要确定任何有趣的孩子何时完成,并且您需要杀死所有孩子。
第一个意味着你不能使用内置的“wait”,因为那会等待全部儿童(或所有列出的儿童,如果有),不适合任何。您基于 USR1 的建议对此非常有效(以及 EXIT)。
第二个要困难得多:因为您使用的是 sudo,所以您实际上没有向进程发送信号的权限;要向进程发送信号,您的用户 ID 必须匹配,或者您必须是 root。
您可以尝试使用基于文件系统或文件句柄的信号或类似的东西,但坦率地说,这在其他脚本语言(python、perl 等)中会更容易理解、可读和可维护,即使如此,它也过于复杂。您最好在目标用户下运行整个脚本。
答案2
如果我建议采用 UNIX 风格的“将复杂的任务划分为更小的任务”,我会从解决 sudo 问题开始,这样您就剩下一个更简单的“当子进程退出时退出 Bash 脚本”问题,其中您的shell 是孩子的直接父母。
#!/bin/sh
exec sudo sh -c '
exit_trap() {
kill # pids
}
trap exit_trap SIGNALS
# run children &
wait # pids
'
请注意,此时,该脚本基本上是单引号中内部脚本的 sudo 化包装器。我不确定这是否值得,但也许您在exec
sudo 调用之前或之后(在这种情况下您想要删除)需要运行额外的代码,这使得这种奇怪的行为值得。