如何在 bash 脚本中等待子进程,如果其中一个失败所以停止所有人

How to wait in bash script to subprocess, if one of them failed so stop everyone

如何在 bash 脚本中等待子进程,如果其中之一 return 退出代码 1 所以我想停止所有子进程。

这就是我尝试做的。 但是有一些问题:

  1. 如果第一个进程比所有其他进程都长,并且另一个进程在后台失败...那么脚本会等待第一个进程完成,即使另一个进程已经失败。

  2. 无法检测到 doSomething 失败,因为我使用管道作为所需的打印格式。

    #!/bin/bash
    
    function doSomething()
    {
            echo [  start ]
    
            sleep 
    
            if [  == 10 ]; then
                    failed
            fi
    
            echo [ sleep  ]: done
    }
    
    function failed(){
                    sleep 2
                    echo ------ process failed ------
                    exit 1
    }
    
    function process_log() {
            local NAME=
            while read Line; do
                    echo [Name ${NAME}]: ${Line}
            done
    }
    
    pids=""
    
    
    (doSomething 4 | process_log 4)&
    pids+="$! "
    
    (doSomething 17 | process_log 17)&
    pids+="$! "
    
    (doSomething 6 | process_log 6)&
    pids+="$! "
    
    (doSomething 10 | process_log 10)&
    pids+="$! "
    
    (doSomething 22 | process_log 22)&
    pids+="$! "
    
    (doSomething 5 | process_log 5)&
    pids+="$! "
    
    
    for pid in $pids; do
           wait $pid || (pkill -P $$ ; break)
    done
    
    echo done program

有人有想法吗?

它的要点是:

#!/bin/bash
set -m # needed for using negative PIDs
trap '{ kill -- $(jobs -rp | sed s/^/-/); wait; } 2> /dev/null' USR1

doSomething() {
    echo "[  start ]"
    sleep ""
    [[  == 10 ]] && failed
    echo "[ sleep  ]: done"
}

failed(){
    echo "------ process failed ------" 1>&2
    kill -USR1 "$$"
}

process_log() {
    local name="" line
    while IFS='' read -r line; do
        echo "[Name $name]: $line"
    done
}

{ doSomething  4 | process_log  4; } &
{ doSomething 17 | process_log 17; } &
{ doSomething  6 | process_log  6; } &
{ doSomething 10 | process_log 10; } &
{ doSomething 22 | process_log 22; } &
{ doSomething  5 | process_log  5; } &

wait

echo "done program"
[Name 4]: [ 4 start ]
[Name 6]: [ 6 start ]
[Name 17]: [ 17 start ]
[Name 5]: [ 5 start ]
[Name 10]: [ 10 start ]
[Name 22]: [ 22 start ]
[Name 4]: [ sleep 4 ]: done
[Name 5]: [ sleep 5 ]: done
[Name 6]: [ sleep 6 ]: done
------ process failed ------
[Name 10]: [ sleep 10 ]: done
done program
解释

想法是让 sub-processes 在失败时通知父脚本(使用 SIGUSR1 信号);主脚本将在收到该信号时杀死所有 sub-processes。
但是有一个问题:杀死 sub-process 的 PID 可能还不够,例如当它当前是 运行 一个带有 | 的命令时。在这些情况下,您需要终止整个 进程组 ,这可以通过使用 set -m 启用 job control 并使用kill 命令中的负 PID。