【问题标题】:Stop bash if any of the functions fail in parallel如果任何函数并行失败,则停止 bash
【发布时间】:2022-12-16 04:30:11
【问题描述】:

我有一个 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 ;}

我注意到即使我在所有函数中都有用于错误处理的 exit 1,但其他函数仍在继续。如果任何函数失败,如何停止 bash 并返回退出代码 1?

我是 BASH 的新手,非常感谢您的帮助!

【问题讨论】:

  • 由于并行进程彼此不了解,我的方法是等到其中一个进程终止,检查退出代码,如果它不为零,则杀死其余(正在运行的)进程。为了管理这个,我会使用一个数组来存储那些仍在运行的后台进程的所有 PID。
  • @user1934428 你能详细说明一下吗?我对如何在捕获退出代码的同时独立等待每个子进程完成感兴趣; wait 内置函数似乎不允许这样做。
  • @Fravadona:见here

标签: bash ubuntu parallels


【解决方案1】:

更新:使用大量同时终止的子进程测试我的原始代码表明需要某种独占锁定机制;我使用广泛可用的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 时自动生成核心转储的效果。如果您运行的操作系统支持SIGUSR1SIGUSR2,那么您可以改用它。

  1. 在脚本的开头,您使用 trap 定义了一些信号侦听器,并关联了一个在捕获指定类型的信号时要运行的命令:
    • EXIT 信号的侦听器(例如由主脚本上下文中的 exit 命令触发)将使用 kill 0 终止脚本及其所有子进程。

    • SIGABRT(由子进程发送)的监听器不仅会生成EXIT信号,还会将退出状态设置为1

    1. 锁定机制是为了防止发送多个SIGABRT信号。

【讨论】:

  • 花了一些时间将您的建议整合到我的代码中。有效!太感谢了!
  • 很高兴您可以在您的代码中实现它。您是否还添加了锁定机制?有必要防止太多的子进程几乎同时“发信号”给主脚本,这会导致脚本僵尸化而其他子进程继续运行;您只需要一个信号即可终止脚本。
【解决方案2】:

GNU 并行--halt-on-error

GNU parallel 是这类应用程序的赢家。安装:

sudo apt install parallel

测试它:

myfunc() {
    echo "start: $1"
    sleep "$1"
    [[ $1 == 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

这:

start: 3
start: 1
start: 2
start: 4

立即出现,一秒后出现end: 1,一秒后出现end: 2,再一秒后出现决赛:

parallel: This job failed:
myfunc 3

在 Ubuntu 22.04 上测试。

笔记:

【讨论】:

    猜你喜欢
    • 2021-08-27
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多