
ファイル記述子6を読むには、<&6
または</dev/fd/6
(別名/proc/self/fd/6
)を使用できます。多くの場合、両方とも同じように効果的です。ただし、対応するファイル記述子がソケットの場合、奇妙なことが起こります。たとえば、
$ bash -c 'ls -l /dev/fd/6;cat /dev/fd/6' 6</dev/tcp/localhost/12345
lrwx------ 1 michas michas 64 Jan 10 19:50 /dev/fd/6 -> socket:[315010]
cat: /dev/fd/6: No such device or address
これはls
記述子が存在することを示します。しかし、このようにデータにアクセスすることは不可能です。使用すると、cat <&6
すべてが正常に戻ります。
ファイル記述子にアクセスする2つの方法の違いは何ですか?
変数に数値が与えられた場合、記述子にアクセスするための良い方法はありますか? (</dev/fd/$fd
はい、しかしそうでは<&$fd
ありません。)
(上記はLinuxでは見ることができますが、OpenBSDでは見ることはできません。 - ファイル記述子が通常の文字デバイスであるように見えます。)
答え1
その理由は、/dev/fd/
Linuxにはソケットを表すエントリからデータを読み取る実装がないためです。ここで推論に関する良い記事を見つけることができます。したがって、そのリンクを呼び出すことができるので、としてマークされますが、stat
意図ls
的に無効になります。
それでは、2番目の部分に進みます。なぜ動作しますかbash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345
?これは/proc
、ファイルシステムではなくソケット/ファイルAPIを使用してソケットを読み取るためです。これが私が観察したものです:
bash
端末で実行されているインスタンスはfd 6を使用してソケットを作成します。- 子プロセスが
bash
実行され、ソケットを 's'dup2(6, 0)
に接続するために呼び出されます。cat
stdin
dup2
呼び出しが失敗しない場合は、catが読み取られますstdin
。
次のように再現して観察できます。
netcat -lp 12345 # in another terminal session (GNU netcat)
strace -f -e trace=open,read,write,dup2 bash -c 'ls -l /dev/fd/6; cat <&6' \
6</dev/tcp/localhost/12345
サブプロセスがfd 6にアクセスできる理由がわからない場合は、bash
ファイル記述子がまだ存在しますfork
。閉じてマークされていない場合はexec
閉じません。
答え2
あなたの直接の質問に答えるために」違いは何ですか? ":
からリダイレクトすると、<&6
シェルはdup2()
システムコールを使用してファイル記述子をコピーします。</dev/fd/6
からリダイレクトしようとしたときopen()
。
カーネルopen()
はソケットをサポートしていません。ソケットは装飾/dev/fd
情報用にのみディレクトリに表示されます。