我有一个 BASH,可以在我的 BASH 中并行运行 3 个函数。
functionA () {
......
my command || { echo "ERROR!!" >> $LOG_FILE ; exit 1 ;}
}
functionB () {
......
my command || { echo "ERROR!!" >> $LOG_FILE ; exit 1 ;}
}
functionC () {
......
my command || { echo "ERROR!!" >> $LOG_FILE ; exit 1 ;}
}
functionA &
functionB &
functionC &
wait
我在所有函数中都有一些这样的错误处理命令:
my command || { echo "ERROR!!" >> $LOG_FILE ; exit 1 ;}
我注意到即使我在所有功能中都有用于错误处理的出口 1,但其他功能仍在继续。如果任何函数失败,如何停止 bash 并返回退出代码 1?
我是 BASH 的新手,感谢任何帮助!
更新: 使用大量子进程同时终止测试我的原始代码表明需要某种独占锁定机制;我使用广泛可用的
mktemp -d
和符号链接实现了一个简单的(即原子的)。
#!/bin/bash
lockdir=$(mktemp -d) || exit "$?"
trap 'exit 1' ABRT
trap 'mv "$lockdir" "$lockdir~" && rm -rf "$lockdir~"; kill 0' EXIT
diex() { ln -s _ "$lockdir/.lock" 2> /dev/null && kill -ABRT "$$"; }
{ sleep 1; echo "ERROR!!"; diex; } &
{ sleep 2; echo "HELLO!!"; } &
wait
注:这里我假设
"$lockdir~"
不存在。如果它对你来说不够好,那么你可以使用 mktemp -d
创建另一个目录,并在删除它之前将其用作垃圾箱。
想法是让子进程在失败时用
kill -ABRT "$$"
通知主脚本。SIGABRT
信号,因为它适合中止的目的,但它具有禁用通常在接收 SIGABRT
时自动生成核心转储的效果。如果您运行的操作系统支持 SIGUSR1
和 SIGUSR2
那么您可以使用它。
trap
定义了一些信号侦听器,并关联了一个在捕获指定类型的信号时要运行的命令:EXIT
信号的侦听器(例如由主脚本上下文中的 exit
命令触发)将使用 kill 0
终止脚本及其所有子进程。
SIGABRT
的监听器(由子进程发送)不仅会产生一个EXIT
信号还会设置退出状态为1
。
SIGABRT
信号。GNU 并行
--halt-on-error now,1
GNU parallel 是这类应用程序的赢家。安装:
sudo apt install parallel
测试一下:
myfunc() {
echo "start: $1"
sleep "$1"
[ $1 -eq 3 ] && exit 1
echo "end: $1"
}
export -f myfunc
parallel --lb --halt-on-error now,fail=1 myfunc ::: 1 2 3 4
echo "exit status: $?"
结果:
start: 3
start: 1
start: 2
start: 4
end: 1
end: 2
parallel: This job failed:
myfunc 3
exit status: 1
所以我们看到
4
从未完成,因为 3
在它之前失败了。
的:
start: 3
start: 1
start: 2
start: 4
立即出现,
end: 1
一秒后,end: 2
再过一秒,再过一秒最后:
parallel: This job failed:
myfunc 3
在 Ubuntu 22.04 上测试。
备注:
之前在 Ubuntu 上与 moreutils parallel 有一些冲突:https://askubuntu.com/questions/12764/where-do-i-get-a-package-for-gnu-parallel 但那已经消失了,
sudo apt install parallel
正常工作
man parallel
文件:
为了向后兼容,这些也有效:
2 现在,失败=1
一些你可能需要的早期版本
--halt-on-error 2
代替
export -f
通过将 Bash 函数导出为环境变量使事情在 Bash 上运行:GNU Parallel 和 Bash 函数:如何运行手册中的简单示例