繰り返し実行されるプログラムの出力を合計するスクリプトのテスト中に理解できない動作が見つかりました。これを再現するには、out
私のプログラムの出力を表すテキストファイルを作成しsum
、このファイルは前の実行から返された値の合計を保持し、そのコピーで始まりますout
。
cat > out << EOF
2 20
5 50
EOF
cp out sum
実行中に奇妙なことが起こります
paste out sum | awk '{$1 += $3; $2 += $4; NF = 2; print}' | tee sum
複数回(15〜20回かかることがあります)実行するたびに、コマンドはsum
その値に値を追加しout
て結果を再作成する必要がありますsum
。私が得るものは予測不可能な回数だけ働いたsum
。
2 20
5 50
後で学びました。作業中の同じファイルに出力をリダイレクトまたはティーイングすることはできません。一時ファイルを使用すると問題は解決しましたが、この動作はまだ混乱しています。
… | tee sum
限られた回数の繰り返しでも機能しますが、… > sum
上書きしないのはなぜですかsum
?なぜ期待どおりに動作しないのですか?
ベストアンサー1
これ、
paste out sum | awk ... | tee sum
競争条件があります。読むためにpaste
開いて、書くために開いて、切ります。シェルはほぼ同時に起動するため、最初にファイルを開くシェルによって異なります。sum
tee
もちろん、実際には、シェルは特定の順序で一度に1つずつユーティリティを起動する必要があります。左から右に実行される可能性があるため、paste
最初に実行される可能性が高いかもしれませんが、これは実装の詳細であり、とにかく実行するタイミングはOSスケジューラによって決定されます。
先に進むと、paste
データはそのまま残り、データを読み取るのに十分な時間があるファイルが開きます。ファイルを読み込む前に開くと、空のtee
ファイルが表示されます。paste
paste
ここでは、
paste out sum | awk ... > sum
シェルは書き込みsum
用に開き、切り捨てられます。これはstartと並行して実行できますが、切り捨てにはpaste
他sum
のユーティリティの起動が含まれていないため、最初に発生する可能性があります。 (リダイレクトを処理するルールと、そのようなパイプラインでコマンドが開始される順序があるかどうかはわかりませんが、それに依存しません。)
sponge
この問題を解決するツールがあります。それに関する質問)。得られた入力を収集し、入力が閉じた後にのみ書き込みます。これはsum
常に正しく更新する必要があります。
paste out sum | awk ... | sponge sum