Bashシェルで次の例を考えてみましょう。
$ echo 'test' | wc -c
5
すべてが期待どおりに動作します。今、私たちはそれを次のように置き換えます。
$ echo 'test' >&0 | wc -c
test
0
これで、0
出力内容が完全に理解されます。echo
すべてが(伝統的に書き込み可能)に転送されましたが、stdin
何も転送されなかったstdout
ため、何もパイプに転送されませんでしたwc
。しかし、出力はコンソールにどのように表示されますか?このtest
行は誰がいつ印刷したのですか?
最後に、3回目のテスト(サポートされているプラットフォームの場合stdbuf
)
$ stdbuf -i0 -o0 -e0 echo 'test' >&0 | wc -c
0
test
ここで何が起こっているのでしょうか?順序がなぜ変わったのですか?
答え1
は端末に接続されているため、実行すると出力がstdin
端末に移動します。通常、標準入力は使用されませんが、たとえば存在します。一方、実行すると、2番目のstdinに接続されたパイプが読み取り専用であるため、「無効なファイル記述子」エラーが発生します。echo
echo 'test' >&0
echo
cat
echo foo | echo test >&0
echo
stdbuf
他のコードスニペットでは、パイプが閉じているという事実に気づくこと(誰もパイプに書き込めないように書き込み側をリダイレクトする)と端末に書き込むこととの間に競争があると思います。これはバッファリングとは関係ありません(とにかく完了したらバッファをフラッシュする必要があるため実際には重要ではありません)、またはを使用して同じ結果を得ることができます。開始速度を遅くする左側のすべてが影響を与えます。また、を使用するとシェルの組み込み実装を実行できますが、またはを使用すると外部実装を実行することに注意してください。より早く組み込まれています。wc
stdin
echo
echo
strace echo ...
env echo ...
echo
echo | wc
echo
stdbuf
env
strace
echo
一般的に言えば、両方のプロセスが同時にどこかに書き込む場合、明示的に同期しない限り、書き込み順序については何の前提もできません。