Bash & (ampersand) 运算符

21

我正在尝试在Bash Shell中并行运行3个命令:

$ (first command) & (second command) & (third command) & wait

这样做的问题是,如果first command失败,例如,退出代码是0(我猜是因为wait成功了)。

期望的行为是,如果其中一个命令失败,则退出代码将为非零(最好停止其他正在运行的命令)。

我该如何实现呢?

请注意,我希望并行运行这些命令!

4个回答

11

我能想到的最好的办法是:

first & p1=$!
second & p2=$!
...

wait $p1 && wait $p2 && ..
或者
wait $p1 || ( kill $p2 $p3 && exit 1 )
...

但是这仍然强制按照进程的顺序进行检查,因此如果第三个进程立即失败,您将不会注意到它,直到第一和第二个完成。


4
这可能适用于您:
parallel -j3 --halt 2 <list_of_commands.txt

这将同时运行3个命令。

如果任何一个正在运行的作业失败,它将终止其余正在运行的作业,然后停止,并返回失败作业的退出代码。


它将并行运行3个命令,但不会满足OP的退出代码要求。 - anubhava
1
@MishaMoroshko 谷歌 GNU Parallel。@anubhava从并行手册中看到 --halt 2 立即终止所有作业并退出,无需清理。退出状态将是失败作业的退出状态。 - potong

2
你应该使用 && 而不是 &。例如:
first command && second command && third command && wait

然而,这不会并行运行您的命令,因为每个随后的命令的执行都依赖于前一个命令的退出代码为0。

4
我认为这对于返回代码会起作用,但不会并行执行命令。 - jcollado
同意并在我的答案中做了记录。但是,如果命令正在并行运行,则无法检查退出代码,因为当第二个命令运行时,前一个命令尚未退出。 - anubhava
1
这里的主要限制是并行运行命令。只要命令能够并行运行且在失败时退出代码为非零,我不介意用更复杂的bash脚本替换这个单行命令。 - Misha Moroshko
请理解,如果命令在并行(或后台)运行,则无法立即获得退出状态,您必须等待命令退出。 - anubhava

0
下面的shell函数将等待作为参数传递的所有PID完成,如果所有PID都没有错误执行,则返回0。
第一个存在错误的PID将导致在它之后出现的PID被终止,并且引起错误的退出代码将被该函数返回。
wait_and_fail_on_first() {
  local piderr=0 i
  while test $# -gt 0; do {
    dpid="$1"; shift
    wait $dpid || { piderr=$?; kill $@; return $piderr ;}
  } done
}

使用方法如下:

(first command) & pid1=$!
(second command) & pid2=$!
(third command) & pid3=$!

wait_and_fail_on_first $pid1 $pid2 $pid3 || {
  echo "PID $dpid failed with code $?"
  echo "Other PIDs were killed"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接