08
、 13
、および 21
ストリームです プロセスのファイル記述子 0、1、2 にそれぞれ付加されます。
端末または端末エミュレーターの対話型シェルのプロンプトで、これら 3 つのファイル記述子はすべて、端末または疑似端末デバイス ファイルを開くことによって取得される同じオープン ファイル記述を参照します (31<のようなもの)。 /コード> ) 読み取り+書き込みモード。
そのインタラクティブ シェルから、リダイレクトを使用せずにスクリプトを開始すると、スクリプトはそれらのファイル記述子を継承します。
Linux では、49
、 53
、 62
77
へのシンボリックリンクです 、 81
、 96
それぞれ、それらのファイル記述子で開かれている実際のファイルへの特別なシンボリック リンクです。
これらは stdin、stdout、stderr ではなく、stdin、stdout、stderr が移動するファイルを識別する特別なファイルです (これらの特別なファイルを持つ Linux 以外のシステムでは異なることに注意してください)。
stdin から何かを読み取るということは、ファイル記述子 0 から読み取ることを意味します (これは、107
によって参照されるファイル内のどこかを指します)。 ).
しかし 116
では 、シェルは標準入力から読み取っていないため、標準入力で開いているファイルと同じファイルを読み取るために新しいファイル記述子を開きます(したがって、標準入力が現在指している場所ではなく、ファイルの先頭から読み取ります)。
端末デバイスが読み取り+書き込みモードで開かれているという特殊なケースを除き、通常、stdout と stderr は読み取り用に開かれません。これらは、書き込むストリームであることを意図しています .したがって、ファイル記述子 1 からの読み取りは、通常は機能しません。 Linux で 128
を開く または 139
読み取り用 (142
のように) ) が機能し、stdout が移動するファイルから読み取ることができます (また、stdout がパイプの場合、パイプの反対側から読み取ることになり、ソケットの場合は、できないため失敗します 開く ソケット)
ターミナルの対話型シェルのプロンプトでリダイレクトなしで実行されるスクリプトの場合、/dev/stdin、/dev/stdout、および /dev/stderr のすべてがその /dev/pts/x ターミナル デバイス ファイルになります。 /P>
これらの特殊ファイルから読み取ると、端末から送信されたもの (キーボードで入力したもの) が返されます。それらに書き込むと、テキストが端末に送信されます (表示用)。
echo $(</dev/stdin)
echo $(</dev/stderr)
同じになります。 156
を展開するには 、シェルはその /dev/pts/0 を開き、166
を押すまで入力した内容を読み取ります 空行に。次に、展開 (末尾の改行を取り除き、分割 + グロブの対象となるもの) を 178
に渡します。 その後、stdout に出力されます (表示用)。
ただし、
echo $(</dev/stdout)
180
で (そして 199
のみ)、 205
内でそれを認識することが重要です 、stdout がリダイレクトされました。今はパイプです。 218
の場合 、子シェル プロセスがファイルの内容を読み取っています (ここでは 221
) をパイプに書き込み、親はもう一方の端から読み取り、展開を構成します。
この場合、その子 bash プロセスが開くと 235
、それは実際にパイプの読み取り側を開いています。そこからは何も生まれません。行き詰まりの状況です。
スクリプトの stdout が指すファイルから読み取りたい場合は、次の方法で回避できます。
{ echo content of file on stdout: "$(</dev/fd/3)"; } 3<&1
これにより、fd 1 が fd 3 に複製されるため、/dev/fd/3 は /dev/stdout と同じファイルを指します。
次のようなスクリプトを使用:
#! /bin/bash -
printf 'content of file on stdin: %s\n' "$(</dev/stdin)"
{ printf 'content of file on stdout: %s\n' "$(</dev/fd/3)"; } 3<&1
printf 'content of file on stderr: %s\n' "$(</dev/stderr)"
次のように実行する場合:
echo bar > err
echo foo | myscript > out 2>> err
249
に表示されます その後:
content of file on stdin: foo
content of file on stdout: content of file on stdin: foo
content of file on stderr: bar
258
から読み取るのとは対照的に 、 266
、 272
、stdin、stdout、および stderr から読み取りたい場合 (これはあまり意味がありません)、次のようにします:
#! /bin/sh -
printf 'what I read from stdin: %s\n' "$(cat)"
{ printf 'what I read from stdout: %s\n' "$(cat <&3)"; } 3<&1
printf 'what I read from stderr: %s\n' "$(cat <&2)"
2 番目のスクリプトを次のように再度開始した場合:
echo bar > err
echo foo | myscript > out 2>> err
283
に表示されます :
what I read from stdin: foo
what I read from stdout:
what I read from stderr:
そして 294
で :
bar
cat: -: Bad file descriptor
cat: -: Bad file descriptor
stdout および stderr の場合、303
ファイル記述子が書き込み用に開かれているため、失敗します 読むのではなく、314
の展開のみ と 321
空です。
次のように呼び出した場合:
echo out > out
echo err > err
echo foo | myscript 1<> out 2<> err
(ここで 330
切り捨てなしで読み取り+書き込みモードで開きます)、341
に表示されます :
what I read from stdin: foo
what I read from stdout:
what I read from stderr: err
そして 357
で :
err
前の 360
が 379
の内容を上書きしていました 383
で 直後にそのファイル内の標準出力位置を残しました。 393
をプライミングした場合 次のような大きなテキストを使用:
echo 'This is longer than "what I read from stdin": foo' > out
その後、404
に入ります。 :
what I read from stdin: foo
read from stdin": foo
what I read from stdout: read from stdin": foo
what I read from stderr: err
412
の仕組みを見る 最初の 427
の後に残っているものを読みました そしてそうすることで、stdout の位置もそれを超えて移動しました 次の 430
後に読み取られたものを出力します。
449
と 455
出力は、それらから読み取るのではなく、書き込むことしかできません。例:
echo "this is stdout" >/dev/stdout
echo "this is stderr" >/dev/stderr
プログラムはデフォルトで stdout に書き込むので、最初のものは次と同等です
echo "this is stdout"
また、次のような方法で stderr をリダイレクトできます
echo "this is stderr" 1>&2