使用 wait (bash posix) 如果脚本中的一个进程失败则失败

使用 wait (bash posix) 如果脚本中的一个进程失败则失败

我正在编写一个脚本,它在后台同时执行一堆命令,然后等待它们全部完成:

#!/bin/sh -fx
./p1 &
./p2 &
./p3 &
./p4 &
./p5 &
wait

问题是,如果这些过程中的一个或多个失败,它就会继续下去。如何同时执行所有这些命令并检查一个或多个命令是否失败?

答案1

您可以等待各个 pid 获取其退出状态:

#! /bin/sh -
set -o xtrace -o noglob

./p1 & p1=$!
./p2 & p2=$!
./p3 & p3=$!
./p4 & p4=$!
./p5 & p5=$!
fail=0
for pid in "$p1" "$p2" "$p3" "$p4" "$p5"; do
  wait "$pid" || fail=$(( fail + 1 ))
done
echo>&2 "$fail failed"
exit "$(( fail > 0 ))"

请注意,我们不一定按照这些进程终止的顺序等待它们,但wait pid仍然应该努力检索 pid 的退出状态,即使是wait在 pid 已经退出后调用 。

另一种方法是使用大多数实现pipefail支持的选项sh将出现在 POSIX 标准的下一版本中:

#! /bin/sh -
set -o xtrace -o noglob -o pipefail
alias r='<&3 3<&- >&4 4>&-'

die() { printf>&2 '%s\n' "$@"; exit 1; }

{
  r ./p1 | r ./p2 | r ./p3 | r ./p4 | r ./p5
} 3<&0 4>&1 || die "At least one of them failed"

我们在管道中启动它们,但不使用管道。我们借助该r别名将这些进程的 stdin 和 stdout 恢复为保存在 fd 3 和 4 上的原始值。


尽管不幸的是dash还没有,尽管大多数其他基于 ash 的 shell 已经支持它。

相关内容