如何在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、按顺序等待它们并求和退出状态更好的解决方案呢?
这里有一个使用等待的简单例子。
运行一些进程:
$ sleep 10 &
$ sleep 10 &
$ sleep 20 &
$ sleep 20 &
然后用wait命令等待他们:
$ wait < <(jobs -p)
或者只是等待(没有争论)。
这将等待后台的所有作业完成。
如果提供了-n选项,则等待下一个作业终止并返回其退出状态。
参见:帮助等待和帮助作业语法。
然而,缺点是这将只返回最后一个ID的状态,因此您需要检查每个子流程的状态并将其存储在变量中。
或者让你的计算函数在失败时创建一些文件(空的或有失败日志的),然后检查该文件是否存在。
$ sleep 20 && true || tee fail &
$ sleep 20 && false || tee fail &
$ wait < <(jobs -p)
$ test -f fail && echo Calculation failed.
我刚刚修改了一个脚本到后台和并行化的过程。
我做了一些实验(在Solaris上使用bash和ksh),发现如果退出状态不为零,'wait'将输出退出状态,或者当没有提供PID参数时,将输出一个返回非零退出的作业列表。如。
Bash:
$ sleep 20 && exit 1 &
$ sleep 10 && exit 2 &
$ wait
[1]- Exit 2 sleep 20 && exit 2
[2]+ Exit 1 sleep 10 && exit 1
Ksh:
$ sleep 20 && exit 1 &
$ sleep 10 && exit 2 &
$ wait
[1]+ Done(2) sleep 20 && exit 2
[2]+ Done(1) sleep 10 && exit 1
这个输出被写入stderr,所以OPs示例的简单解决方案可以是:
#!/bin/bash
trap "rm -f /tmp/x.$$" EXIT
for i in `seq 0 9`; do
doCalculations $i &
done
wait 2> /tmp/x.$$
if [ `wc -l /tmp/x.$$` -gt 0 ] ; then
exit 1
fi
虽然这:
wait 2> >(wc -l)
也将返回一个计数,但不包含TMP文件。这也可以这样使用,例如:
wait 2> >(if [ `wc -l` -gt 0 ] ; then echo "ERROR"; fi)
但是这并不比tmp文件有用多少。我找不到一种有效的方法来避免tmp文件,同时也避免在子shell中运行“等待”,这根本不会起作用。