次のテストコードは、「無効なファイル記述子」エラーを提供します。なぜこれが起こるのですか?これは、ファイル記述子とパイプとの相互作用を理解するためのテストコードだけです。
例1)
❯ echo "hello" 1>&2 1>&- |& echo "world"
world
zsh: 1: bad file descriptor
例2)
echo "hello" 1>&2 1>&- | cat <<< "world"
zsh: write error: bad file descriptor
world
例3)
# Does not give error
❯ echo "helloworld" >&-
# Gives stdin? error
❯ cat <<< "helloworld" >&-
cat: stdin: Bad file descriptor
stderrを閉じるかstdoutとstderrの両方を閉じても、「無効なファイル記述子」エラーは発生しません。たとえば、次のいずれもエラーは発生しません。
❯ echo "hello" 1>&2 2>&- |& echo "world"
❯ echo "hello" 2>&1 2>&- |& echo "world"
❯ echo "hello" 1>&2 1>&- 2>&- |& echo "world"
ベストアンサー1
|&
はい2>&1 |
(例:録音された)。左側の標準出力は、他のリダイレクトが行われる前にパイプの書き込み側に接続されますが、標準エラーは最後にその時点の標準出力に接続されます。これは、標準出力がリダイレクトされたり、例のように閉じられた場合に影響します。foo 1>&- |& bar
、またはそれと同等のものを使用するか、単にfoo 1>&- 2>&1 | bar
使用するfoo 1>&- 2>&1
と、fd 2からfd 1へのリダイレクトが適用されたときにファイル記述子1に何もありません。
を使用する場合は、foo 1>&2 1>&- | bar
最初にfoo
標準出力をパイプの書き込み端に接続してから(開いていると仮定multios
)、組み込み1>&2
のT字型プロセス用のパイプを作成します。このプロセスは、オペレータ|
によって生成されたパイプとファイルに書き込みます。当時の記述子2(すなわち、端末)。その後、標準出力が1>&-
閉じるため、foo
標準出力に書き込もうとすると、この書き込みは失敗します。ティーのようなプロセスが書く場所がいくら多くても1>&-
入力を受けられません。
^ドキュメントに指定されたものが見つかりませんが、これはシェルが伝統的に行ったことです。POSIXで指定。不明な場合は、ソースコード、システムコールのトレースを確認したり、さまざまなリダイレクト実験(これまでに行った実験など)の結果から推論したりできます。