Bash スクリプトの「while read」ループは、GNU Parallel で実行すると「broken pipe」エラーを引き起こします。

Bash スクリプトの「while read」ループは、GNU Parallel で実行すると「broken pipe」エラーを引き起こします。

GNU Parallel メーリング リストによると、これは GNU Parallel 固有の問題ではありません。ここで問題を投稿するよう提案されました。

私が受け取っているエラーは「壊れたパイプ」エラーですが、まずは問題の背景とこのエラーの原因を説明する必要があると思います。これは、GNU Parallel で「while read」ループを含む bash スクリプトを使用しようとすると発生します。

次のような基本的な bash スクリプトがあります。

#!/bin/bash
# linkcheck.sh

while read domain
do
host "$domain"
done

大きなリスト(たとえば 250 MB)をパイプで送信するとします。

cat urllist | ./linkcheck.sh

250 MB 相当の URL に対してホスト コマンドを実行すると、かなり時間がかかります。処理速度を上げるには、入力をパイプする前にチャンクに分割し、複数のジョブを並列で実行します。GNU Parallel は、これを実行できます。

cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}

{} は、urllist の内容に 1 行ずつ置き換えられます。システムのデフォルト設定では、parallel のインスタンスごとに 500 程度のジョブを実行できると仮定します。この制限を回避するには、Parallel 自体を並列化します。

cat urllist | parallel -j10 --pipe parallel -j0 ./linkcheck.sh {}

これは約5000のジョブを実行します。また、残念なことに、「パイプが壊れています」というエラーも発生します。(bash FAQ)しかし、while read ループを削除し、{} に入力されたものから直接入力を取得すると、スクリプトは動作し始めます。例:

#!/bin/bash
# linkchecker.sh

domain="$1"
host "$1"

while read ループではなぜ動作しないのでしょうか? SIGPIPE 信号をオフにして「壊れたパイプ」メッセージを停止するだけで安全ですか、それともデータ破損などの副作用がありますか?

読んでくれてありがとう。

答え1

だからした

cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}

正しく動作しますか?問題の一部は、2番目のを省略したことにあると思います--pipe

cat urllist | parallel -j10 --pipe parallel -j0- パイプ./linkcheck.sh {}

 


ところで、言う必要はありません

1ファイル|何らかのコマンド

これをいつでも変更することができます

何らかのコマンド<1ファイル

catその結果、プロセスが 1 つ減り (パイプも 1 つ減ります)。(複数の入力ファイルがある場合に使用するのが適切/必要な場合があります。)

答え2

パイプがまだ開いている間に子をフォークして linkcheck.sh の別のコピーを実行する時点と、子が実際に読み取りを試みる時点の間のウィンドウが原因で、悪い競合状態が発生し、エラーが発生している可能性があると思われます。そのウィンドウでは、別のコピーが EOF を読み取り、パイプが閉じています。

関連情報