我正在编写一个脚本,它在后台同时执行一堆命令,然后等待它们全部完成:
#!/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 已经支持它。