mic*_*has 11 linux bash file-descriptors socket
要从文件描述符 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
Run Code Online (Sandbox Code Playgroud)
这里ls
显示描述符确实存在。但是无法通过这种方式访问数据。如果我cat <&6
改用一切正常。
两种访问文件描述符的方式有什么区别?
如果在变量中给出数字,是否有一种访问描述符的好方法?(</dev/fd/$fd
会起作用,但<&$fd
不会。)
(上述情况可以在 linux 上观察到,但在 OpenBSD 上不能观察到。- 似乎该文件描述符是那里的常规字符设备。)
之所以如此,是因为/dev/fd/
在 Linux 上没有实现从代表套接字的条目中读取数据。你可以在这里找到一篇关于推理的好文章。因此您可以调用stat
该链接,这就是您看到它的原因ls
,但故意禁止访问。
现在是第二部分 - 为什么bash -c 'ls -l /dev/fd/6; cat <&6' 6</dev/tcp/localhost/12345
有效?那是因为套接字是使用套接字/文件 API 读取的,而不是/proc
文件系统。这是我观察到的情况:
bash
在终端中运行的实例使用 fd 6 创建套接字。bash
运行并调用dup2(6, 0)
,以便将您的套接字附加为cat
's 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
Run Code Online (Sandbox Code Playgroud)
如果您想知道为什么bash
子进程可以访问 fd 6 - 文件描述符存活fork
,并且如果它们没有被标记为关闭exec
,它们也不会在那里被关闭。