Bashプロンプトが表示された、同じユーザーの2つのウィンドウ。ウィンドウ1で次のように入力します。
$ mkfifo f; exec <f
そのため、bashは名前付きパイプf
にマップされているファイル記述子0から読み取ろうとしています。ウィンドウ2で次のように入力します。
$ echo ls > f
ここで、window-1はlsを出力し、シェルは終了します。どうして?
次の実験:exec <f
でwindow-1をもう一度開きます。ウィンドウ2で次のように入力します。
$ exec 3>f
$ echo ls >&3
上記の最初の行の後、window-1はウェイクアップし、プロンプトを出力します。どうして?上記の2行目以降、window-1はls
出力を出力し、シェルは存続します。どうして?実際、現在window-2では、echo ls > f
はwindow-1シェルを閉じません。
答えは、名前付きパイプを参照するwindow-2からのファイル記述子3のexistenceに関係する必要がありますか?!
これは、ファイル記述子のclosingに関係しています。
最初の例では、echo
はシェルがf
と接続するために開く標準出力ストリームに書き込み、終了すると記述子が閉じられます(シェルによって)。受信側では、標準入力ストリーム(f
に接続されている)から入力を読み取るシェルがls
を読み取り、ls
を実行してから、エンドオブエンドのために終了します。 -標準入力のファイル条件。
名前付きパイプへのすべてのライター(この例では1つのみ)がパイプの終わりを閉じたため、ファイルの終わり条件が発生します。
2番目の例では、exec 3>f
はf
に書き込むためにファイル記述子3を開き、次にecho
がls
に書き込みます。 echo
コマンドではなく、ファイル記述子が開かれたのはシェルです。 exec 3>&-
を実行するまで、記述子は開いたままになります。受信側では、標準入力ストリーム(f
に接続されている)から入力を読み取るシェルがls
を読み取り、ls
を実行して、さらに入力を待機します(ストリームはまだ開いています)。
ストリームへのすべての書き込み(exec 3>f
およびecho
を介したシェル)がnotでパイプの終わりを閉じているため、ストリームは開いたままです(exec 3>f
isまだ有効です)。
上記のecho
については、まるで外部コマンドであるかのように書いています。ほとんどの場合、シェルに組み込まれています。それでも効果は同じです。
@Kusalanandaと@ikkachuの2つの回答を読んだら、理解できたと思います。ウィンドウ1で、シェルはパイプの書き込み側を開いて閉じるための何かを待機しています。書き込み終了が開かれると、ウィンドウ1のシェルはプロンプトを出力します。書き込みが終了すると、シェルはEOFを取得して終了します。
Window-2側では、私の質問で説明した2つの状況があります。echo ls > f
の最初の状況では、ファイル記述子3がないため、echo
が生成され、そのstdin
とstdout
は次のようになります。
0 --> tty
1 --> f
その後、echo
は終了し、シェルは両方の記述子を閉じます。ファイル記述子1が閉じており、f
を参照しているため、f
の書き込み側が閉じているため、EOFがwindow-1になります。
2番目の状況では、シェルでexec 3>f
を実行し、シェルに次の環境を適用させます。
bash:
0 --> tty
1 --> tty
2 --> tty
3 --> f
ここでecho ls >& 3
を実行し、シェルは次のようにecho
のファイル記述子を割り当てます。
echo:
0 --> tty
1 --> f # because 3 points to f
2 --> tty
次に、シェルはf
を含む上記の3つの記述子を閉じますが、f
にはシェル自体からの参照がまだ残っています。これが重要な違いです。 exec 3>&-
で記述子3を閉じると、最後に開いた参照が閉じ、@ Kusalanandaが述べたようにEOFをwindow-1に引き起こします。