twice
出力を2回見たいのですが、このスクリプトは一度だけ出力します。
dump() {
(sleep 1; cat) > "$1"
}
(sleep 0; echo "twice") | tee >(dump "./a.txt")
echo "$(< "a.txt")"
2回視聴するには、睡眠スケジュールを調整する必要がありました。
dump() {
(sleep 0; cat) > "$1"
}
(sleep 1; echo "twice") | tee >(dump "./a.txt")
echo "$(< "a.txt")"
ここで競合状態の原因は何ですか?
ベストアンサー1
プロセス交換呼び出しはdump
非同期プロセスとして実行されます。これはtee
、出力がここに書き込まれ、パイプラインが完了したことを意味します。tee
作成すると出力がバッファリングされ、パイプが完了します。データ量がパイプバッファサイズを超えています。、使用するのをtee
待つ必要があり、元のコードはほとんど機能します。dump
質問で行ったように少量のデータしか書き込めないと仮定すると、a.txt
パイプが終了した直後にファイルに何も書き込む機会が生じる前にデータを読み取りますdump
(データが保留中の状態でまだバックグラウンドで眠っています)。パイプバッファ)。
エラーコードを実行した後にファイルを見ると、a.txt
文字列が含まれていることがわかりますtwice
。したがって、sleep 1
関数に与えられたわずかな遅延の後、最終的にはその位置に到達します。
パイプが早期にシャットダウンするのを防ぐには、cat
最後に次を追加します。
dump() {
(sleep 1; cat) > "$1"
}
(sleep 0; echo "twice") | tee >(dump "./a.txt") | cat
echo "$(< "a.txt")"
cat
これで、プロセスは出力がパイプを介して到着するのを待たなければならないために機能しますdump
(そうではありませんが、それはわかりません)。これにより、dump
呼び出しが返されるまでパイプのシャットダウンが遅れます。この時点でデータが記録され、a.txt
スクリプトの最後のコマンドを使用して取得できます。
パイプラインでプロセスを同期する唯一のものはI / Oです。これは、前のプロセスからデータを読み取り、それを次のプロセスに書き込むことです。プロセスがある時点で前のステップのデータを読み取ろうとすると、読み取るデータがあるか、前のステップでパイプの端を閉じるまでブロックされます。
cat
デフォルトは標準入力から読み取ることです。追加された標準入力は、cat
パイプラインの前の段階で標準出力tee
と手順の置き換えに接続されます。dump
ユーティリティcat
は、読み取る内容がなくなるまで読み込みます。これはtee
どちらも実行が完了するまでdump
発生しません。
コードの整理されたバージョン:
dump() {
sleep 1
cat >"$1"
}
echo twice | tee >(dump ./a.txt) | cat
cat a.txt