並列プロセスを実行し、両方が完了したら出力を結合する方法

並列プロセスを実行し、両方が完了したら出力を結合する方法

私は、約 5 つか 6 つの異なるプログラムにデータをパイプし、最終結果をタブ区切りファイルに出力する bash シェル スクリプトを持っています。

次に、別の同様のデータセットに対して同じ操作を再度実行し、2 番目のファイルに出力します。

次に、両方のファイルを別のプログラムに入力して比較分析します。たとえば、簡素化するために

Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv
AnalysisProg -i Data1res.csv Data2res.csv

私の質問は、ステップ 1 とステップ 2 を同時に実行し (例: & を使用)、両方が完了したときにのみステップ 3 (AnalysisProg) を起動するにはどうすればよいかということです。

THX

ps AnalysisProg はストリームまたは FIFO では動作しません。

答え1

を使用しますwait。例:

Data1 ... > Data1Res.csv &
Data2 ... > Data2Res.csv &
wait
AnalysisProg

意思:

  • Data1 と Data2 パイプをバックグラウンドジョブとして実行する
  • 二人とも終わるまで待つ
  • AnalysisProgを実行します。

例えば、この質問

答え2

ファイルが 2 つしかない場合は、cxw の回答が間違いなく最適なソリューションです。2 つのファイルが単なる例で、実際には 10000 個のファイルがある場合、サーバーに過負荷がかかるため、「&」ソリューションは機能しません。そのためには、GNU Parallel のようなツールが必要です。

ls Data* | parallel 'cat {} | this | that |theother | grep |sed | awk |whatever > {}res.csv
AnalysisProg -i *res.csv

GNU Parallel の詳細については、以下を参照してください。

答え3

これを行う 1 つの方法は次のようになります。

AnalysisProg <<PREPROCESS /dev/stdin
$( 
{   process1=$( pipe | line | 1 >&2 & echo $! )
    process2=$( pipe | line | 2 >&2 & echo $! )
    while ps -p $process1 $process2 >/dev/null; do
        sleep 1
    done
} 2>&1
)
#END
PREPROCESS

この方法では、両方のパイプラインをバックグラウンドで実行しますが、出力をstdinに結合する前に実行が完了するのを待ってから、ヒアドキュメントで評価され、AnalysisProgに渡されます。waitこれはwhile psループしますが、シェルによっては、waitプロセスを待つように指示すると、反対するかもしれません現在のシェルの子ではありません。

また、上記の方法では出力が照合されるため、両方のプロセスが同時に書き出すことに注意してください。代わりに、それらを別々にしたい場合、または一方を他方に追加したい場合は、次のようにすることができます。

AnalysisProg 3<<PREPROCESS /dev/fd/3 /dev/stderr
$(
process1=$(... >&2 ...) 2>/dev/fd/3
...
} 3>/dev/fd/3 2>/dev/stderr
)

これらのコンセプトについては以前にも紹介しました。おそらく最も良いデモはここそしてここ

答え4

これを使ってみてください。

rm -f Data1Res.csv
rm -f Data2Res.csv
Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv &
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv &
while true
do
  ps aux | grep -v grep | grep -i -E 'Data1Res.csv|Data2Res.csv' &> /dev/null
  if [ $? -ne 0 ]
  then
    AnalysisProg -i Data1res.csv Data2res.csv
    exit 0
  fi
done

関連情報