ale*_*rov 7 bash io-redirection socket
我正在处理一些rc.local在启动时运行的脚本,我注意到输出重定向的工作方式很奇怪。
如果我写了类似的东西echo "foo" >&1,它最终会出现在系统日志中,一切都很好。
但是当我写echo "foo" >>/dev/stdout, or 时echo "foo" >>/proc/self/fd/1,我收到一个错误,说没有这样的设备或地址。
进一步调查显示,这/proc/self/fd/1实际上是一个套接字。ls -l /proc/self/fd在rc.local印刷品中包括以下内容:
lr-x------. 1 root root 64 Jul 14 05:28 0 -> /dev/null
lrwx------. 1 root root 64 Jul 14 05:28 1 -> socket:[18485]
lrwx------. 1 root root 64 Jul 14 05:28 2 -> socket:[18485]
lr-x------. 1 root root 64 Jul 14 05:28 255 -> /etc/rc.d/rc.local
Run Code Online (Sandbox Code Playgroud)
所描述的行为可以很容易地重现nc。首先,找出哪个文件描述符绑定到套接字。您可以通过nc -l -p 25566 -c "ls -l /proc/self/fd"在第一个终端然后telnet localhost 25566在其他终端发出来完成。就我而言,它是第 5 个描述符。
好的。然后,要重现该问题,请在第一个终端中:
nc -l -p 25566 -c "echo 'hello' >&5"
Run Code Online (Sandbox Code Playgroud)
在第二个终端:
telnet localhost 25566
Run Code Online (Sandbox Code Playgroud)
您将在有关建立和关闭连接的 telnet 消息之间的第二个终端输出中看到“hello”。
现在文件描述符伪文件的情况来自/proc:
第一个终端:
nc -l -p 25566 -c "echo 'hello' >/proc/self/fd/5"
Run Code Online (Sandbox Code Playgroud)
第二个终端:
telnet localhost 25566
Run Code Online (Sandbox Code Playgroud)
现在第二个终端只包含关于连接建立和立即关闭的 telnet 消息,第一个终端显示错误:sh: /proc/self/fd/5: No such device or address。
编辑:操作系统是 Fedora 23 i686 服务器
所以,问题。>&1和 和有>/proc/self/fd/1什么区别?是否有一些通用且可靠的方法将输出重定向到某个文件,这与当前的标准输出完全对应?
谢谢你。
编辑2:
为清楚起见,上述情况下 Fedora 23 i686 的准确输入/输出:
Terminal 1 | Terminal 2
$ nc -l -p 25566 -c 'ls -go /proc/self/fd' |
| $ telnet localhost 25566
| Trying ::1...
| Connected to localhost.
| Escape character is '^]'.
| total 0
| lr-x------ 1 64 Jul 14 08:56 0 -> pipe:[19687]
| l-wx------ 1 64 Jul 14 08:56 1 -> pipe:[19688]
| lrwx------ 1 64 Jul 14 08:56 2 -> /dev/tty2
| lr-x------ 1 64 Jul 14 08:56 3 -> pipe:[19687]
| lr-x------ 1 64 Jul 14 08:56 4 -> /proc/1285/fd
| lrwx------ 1 64 Jul 14 08:56 5 -> socket:[19686]
| l-wx------ 1 64 Jul 14 08:56 7 -> /pipe:[19688]
| Connection closed by foreign host.
$ nc -l -p 25566 -c "echo 'hi' >&5" |
| $ telnet localhost 25566
| Trying ::1...
| Connected to localhost.
| Escape character is '^]'.
| hi
| Connection closed by foreign host.
$ nc -l -p 25566 -c "echo 'hi' >/proc/self/fd/5" |
| $ telnet localhost 25566
| Trying ::1...
| Connected to localhost.
sh: /proc/self/fd/5: No such device or address | Escape character is '^]'.
| Connection closed by foreign host.
$ | $
Run Code Online (Sandbox Code Playgroud)
使用>&N. 它是便携式的,正如您所见,实际上可以与套接字一起使用。
您将使用的唯一原因/proc/self/fd是您正在运行一个需要文件名的程序,并且不能被告知使用已经打开的文件描述符。例如<(cmd...)重定向使用它,因为几乎所有命令行实用程序都可以打开由名称指向的文件,但并非所有都直接支持预先打开的文件描述符。
不过,您的 shell 可以使用预先存在的文件描述符,因此无需通过/proc.
此外,/proc/NNN/fd/特定于 Linux,并要求您安装了/proc. 在我的Linux系统,/dev/stdout,/dev/fd/*和其他人是符号链接/proc/self/fd/*等等,所以他们要求/proc太多。在其他 Unix 上,它们可能会有所不同。根据对一个较旧问题的回答, /dev/stdout特别将其列为 POSIX 之外。
至于为什么重定向不能像您尝试的那样工作:尝试使用strace,两者之间的区别在于,对于>&N重定向,bash调用dup()文件描述符,而>/proc/self/fd/N它只是尝试将其作为普通文件打开open()。显然proc不支持像这样打开套接字的新副本,所以调用失败。流套接字几乎是点对点链接,因此禁止打开新副本似乎并不太不自然。但是为什么它适用于管道或带有dup,我不知道。
$ ls -l /proc/self/fd/3
lrwx------ 1 itvirta itvirta 64 Jul 14 18:24 /proc/self/fd/3 -> socket:[168157]
$ strace bash -c "echo foo >>/proc/self/fd/3" 2>&1 | grep open.*proc/self
open("/proc/self/fd/3", O_WRONLY|O_CREAT|O_APPEND, 0666) = -1 ENXIO (No such device or address)
Run Code Online (Sandbox Code Playgroud)
同时这个答案有关于便携性的一些信息/proc/NNN/fd