73958
bash で２つの時間のかかるコマンドを並列実行したいです  
それだけなら & つければいいだけなんですが  
両方の完了を待ってから後続の処理を続けたいので  
バリア同期みたいなのを取る方法ってありますか？

またどれか１つでもエラー (exit code 非０) だったら処理を中断したいんですが  
バックグラウンドジョブのステータスコードをとる方法ってあったりしますか？

```

    #!/bin/bash
    
    (sleep 10; ls abc; RESULT1=$?; COMPLETE1=1; echo $COMPLETE1) & # エラー
    (sleep  5; ls;     RESULT2=$?; COMPLETE2=2; echo $COMPLETE2) & # 正常
    
    while [ -z $COMPLETE1 -o -z $COMPLETE2 ]
    do
      echo "COMPLETE=$COMPETE1,$COMPLETE2"
      sleep 1
    done
    
    echo "RESULT1=$RESULT1"
    echo "RESULT2=$RESULT2"
    
```

こうかいてもバックグラウンドの別プロセスで代入した環境変数って読み出せないんですよね…
CC BY-SA 4.0
2021-02-12T08:06:06.293
73951
2021-02-13T06:41:53.617
2021-02-12T08:19:34.400
question
bash
bash で並列実行時に完了待ちおよびエラー検知する方法
> bash で２つの時間のかかるコマンドを並列実行したいです  
>  それだけなら & つければいいだけなんですが  
>  両方の完了を待ってから後続の処理を続けたいので  
>  バリア同期みたいなのを取る方法ってありますか？

waitを使えばできます。

```

    (sleep 10; ls abc; RESULT1=$?; COMPLETE1=1; echo $COMPLETE1) & # エラー
    (sleep  5; ls;     RESULT2=$?; COMPLETE2=2; echo $COMPLETE2) & # 正常
    wait
    
```

上の例では、２つのコマンドの終了を親プロセスのwaitで待ち合わせています。

> またどれか１つでもエラー (exit code 非０) だったら処理を中断したいんですが  
>  バックグラウンドジョブのステータスコードをとる方法ってあったりしますか？

子供のプロセスから親プロセスに情報を通知するのに環境変数は使えません。  
なんらかの方法で子供のプロセスと親プロセスで通信する必要があります。

紹介するスクリプトはcoprocを使った通信の例です。coprocはbash 4.x以上で使えます。  
コマンドcoprocでcoprocessを生成すると、coprocessの標準入出力を親プロセスから読み書きできます。  
スクリプトの例ではcoprocessの標準出力を配列result[0]で読み取っています。  
※今回は使っていませんが、親プロセスでresult[1]に書き込むとcoprocessの標準入力から読み込むことができます。

標準出力をcoprocessの通信で使うため、親プロセスの標準出力(1)をディスクリプタ(3)に複製し、coprocessから実行するコマンドの標準出力を本来の標準出力に出力できるように、複製したディスクリプタ(3)に割り当てし直しています。

【スクリプトの例(qwqw.sh)】

```

    #!/bin/bash
    cmd1='sleep 20; ls abc; RESULT1=$?; COMPLETE1=1; echo $COMPLETE1;exit ${RESULT1}'
    cmd2='sleep  5; ls;     RESULT2=$?; COMPLETE2=2; echo $COMPLETE2;exit ${RESULT2}'
    cprc() {
        (cmd="${cmd1}";(eval "${cmd}" >&3)& cmd_pid=$!;printf "start %s %s\n" "${cmd_pid}" "${cmd}" ;wait ${cmd_pid};ret=$?;printf "end %s %s %s\n" "${cmd_pid}" "${ret}" "${cmd}" ) &
        (cmd="${cmd2}";(eval "${cmd}" >&3)& cmd_pid=$!;printf "start %s %s\n" "${cmd_pid}" "${cmd}" ;wait ${cmd_pid};ret=$?;printf "end %s %s %s\n" "${cmd_pid}" "${ret}" "${cmd}" ) &
        wait
    }
    
    exec 3>&1
    coproc result  { cprc ; }
    
    while read -u "${result[0]}" para1 para2 para3 para4
    do
        case ${para1} in
        start) printf "start pid=%s command=[%s]\n" "${para2}" "${para3}""${para4}"
            ;;
        end) printf "end pid=%s exit code=%s command=[%s]\n" "${para2}" "${para3}" "${para4}"
            ;;
        esac
    done
    
```

【実行結果】

```

    $ bash qwqw.sh
    start pid=29700 command=[sleep20; ls abc; RESULT1=$?; COMPLETE1=1; echo $COMPLETE1;exit ${RESULT1}]
    start pid=29701 command=[sleep5; ls;     RESULT2=$?; COMPLETE2=2; echo $COMPLETE2;exit ${RESULT2}]
    qw.sh  qwqw.sh
    2
    end pid=29701 exit code=0 command=[sleep  5; ls;     RESULT2=$?; COMPLETE2=2; echo $COMPLETE2;exit ${RESULT2}]
    ls: 'abc' にアクセスできません: そのようなファイルやディレクトリはありません
    1
    end pid=29700 exit code=2 command=[sleep 20; ls abc; RESULT1=$?; COMPLETE1=1; echo $COMPLETE1;exit ${RESULT1}]
    
```

実行するコマンドは「質問にあるコマンド」の最後に明示的にexit codeを設定するコードを追加しています。  
スクリプトの例では実装していませんが、実行したコマンドのexit codeを判定すれば処理を中断することもできます。
CC BY-SA 4.0
2021-02-12T13:59:15.780
73958
2021-02-13T06:41:53.617
2021-02-13T06:41:53.617
35558
35558
73951
answer