2つの非同期サブシェルコマンドを共有標準出力に安全に書き込むことはできますか?

2つの非同期サブシェルコマンドを共有標準出力に安全に書き込むことはできますか?

非同期的に実行される2つのbourne(または重要な場合はbash)サブシェルコマンドでstdoutを上書きできますか?

(tail -f ./file1 & tail -f ./file2) | cat

行の順序は気にせず、各出力行が1つの入力行で構成される点だけ異なります。一部の行が部分的に隠れているかインターリーブされる可能性があることが心配です。

私はそれぞれ独自のラインを1,500万回出力する4つのコマンドを実行してこれをテストしました。うまくいくようですが、失敗すると予想しました。

誰かがこれがどのように壊れないかを説明できますか?各サブシェルはバッファリングされており、一度に1つのサブシェルのみを標準出力に書き込むことができますか?またはこれがどのように管理されるか。

もっと良い方法がありますか?

(私がそうであることを気にしないでください。使用tail上記のサブシェルでは例示目的。実際には、一度に1行ずつ標準出力に連続して出力する2つの異なるコマンドを実行したいと思います。 )

ベストアンサー1

シェルはそこにほとんど関与していません。彼らがすることはパイプラインを生成し、この3つのコマンドを実行することだけです。その後、このコマンドはシェルとは無関係に並列に実行されます。

ここで重要なことは、両方のtailコマンドが同じパイプの同じ書き込みの最後にファイル記述子を書き込むことです。

これにより:

printf foo1 >> file1; sleep 1
printf foo2 >> file2; sleep 1
printf 'bar1\n' >> file1; sleep 1
printf 'bar2\n' >> file2

あなたが見ることができるもの:

foo1foo2bar1
bar2

なぜならそう書かれているからです。コマンドが以下を出力することを確認する必要があります。いっぱい一度に 1 つの行を書き込み、行は PIPE_BUF (Linux の場合は 4096 バイト) より小さく、write() がアトミックであることを保証します (すべてが完全で累積サイズが小さい場合は複数の行全体を同時に書き込むこともできます) 。 PIPE_BUFより)。

GNUを使用すると、grep次のコマンドを渡してこれを実行できます。grep --line-buffered '^'

(tail -f ./file1 | grep --line-buffered '^' &
 tail -f ./file2 | grep --line-buffered '^') | cat

これにより、2つのコマンド出力の各行にwrite()システムコールが含まれます(コマンドが出力の最後の行を終了しない場合は、行が不足している行が追加さgrepれます)。

おすすめ記事