如何在bash脚本中等待从该脚本派生的几个子进程完成,然后在任何子进程以code !=0结束时返回退出代码!=0?

简单的脚本:

#!/bin/bash
for i in `seq 0 9`; do
  doCalculations $i &
done
wait

上面的脚本将等待所有10个子进程,但它总是给出退出状态0(参见help wait)。我如何修改这个脚本,以便它将发现衍生子进程的退出状态,并在任何子进程以code !=0结束时返回退出代码1 ?

有没有比收集子进程的pid、按顺序等待它们并求和退出状态更好的解决方案呢?


当前回答

#!/bin/bash
set -m
for i in `seq 0 9`; do
  doCalculations $i &
done
while fg; do true; done

Set -m允许您在脚本中使用fg和bg Fg除了将最后一个进程放在前台之外,它的退出状态与它所前台的进程相同 而当任何fg以非零退出状态退出时,fg将停止循环

不幸的是,当后台进程以非零退出状态退出时,这将无法处理这种情况。(循环不会立即终止。它将等待前面的进程完成。)

其他回答

我已经尝试过了,并结合了其他例子中最好的部分。该脚本将在任何后台进程退出时执行checkpid函数,并输出退出状态而不诉诸轮询。

#!/bin/bash

set -o monitor

sleep 2 &
sleep 4 && exit 1 &
sleep 6 &

pids=`jobs -p`

checkpids() {
    for pid in $pids; do
        if kill -0 $pid 2>/dev/null; then
            echo $pid is still alive.
        elif wait $pid; then
            echo $pid exited with zero exit status.
        else
            echo $pid exited with non-zero exit status.
        fi
    done
    echo
}

trap checkpids CHLD

wait

http://jeremy.zawodny.com/blog/archives/010717.html:

#!/bin/bash

FAIL=0

echo "starting"

./sleeper 2 0 &
./sleeper 2 1 &
./sleeper 3 0 &
./sleeper 2 0 &

for job in `jobs -p`
do
echo $job
    wait $job || let "FAIL+=1"
done

echo $FAIL

if [ "$FAIL" == "0" ];
then
echo "YAY!"
else
echo "FAIL! ($FAIL)"
fi

我认为并行运行作业并检查状态的最直接方法是使用临时文件。已经有几个类似的答案(例如nietzsche -jou和mug896)。

#!/bin/bash
rm -f fail
for i in `seq 0 9`; do
  doCalculations $i || touch fail &
done
wait 
! [ -f fail ]

上面的代码不是线程安全的。如果你担心上面的代码会同时运行,最好使用一个更独特的文件名,比如fail.$$。最后一行是满足需求:“当任何子进程以code !=0结束时,返回退出代码1 ?”我又加了一条要求,要清理干净。这样写可能会更清楚:

#!/bin/bash
trap 'rm -f fail.$$' EXIT
for i in `seq 0 9`; do
  doCalculations $i || touch fail.$$ &
done
wait 
! [ -f fail.$$ ] 

下面是一个类似的代码片段,用于从多个作业收集结果:我创建一个临时目录,在一个单独的文件中描述所有子任务的输出,然后转储它们以供查看。这和问题不太匹配——我把它作为奖励扔进去:

#!/bin/bash
trap 'rm -fr $WORK' EXIT

WORK=/tmp/$$.work
mkdir -p $WORK
cd $WORK

for i in `seq 0 9`; do
  doCalculations $i >$i.result &
done
wait 
grep $ *  # display the results with filenames and contents
#!/bin/bash
set -m
for i in `seq 0 9`; do
  doCalculations $i &
done
while fg; do true; done

Set -m允许您在脚本中使用fg和bg Fg除了将最后一个进程放在前台之外,它的退出状态与它所前台的进程相同 而当任何fg以非零退出状态退出时,fg将停止循环

不幸的是,当后台进程以非零退出状态退出时,这将无法处理这种情况。(循环不会立即终止。它将等待前面的进程完成。)

下面的代码将等待所有计算的完成,并在任何doccalculation失败时返回退出状态1。

#!/bin/bash
for i in $(seq 0 9); do
   (doCalculations $i >&2 & wait %1; echo $?) &
done | grep -qv 0 && exit 1