当 sudo 子进程退出时退出 Bash 脚本

当 sudo 子进程退出时退出 Bash 脚本

我正在尝试从 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 化包装器。我不确定这是否值得,但也许您在execsudo 调用之前或之后(在这种情况下您想要删除)需要运行额外的代码,这使得这种奇怪的行为值得。

相关内容