默认情况下打开标准文件描述符 <= 2。程序可以写入或读取 2 之后的文件描述符,而无需使用open
系统调用来获取此类描述符。然后,该程序可以在其手册中公布它正在使用哪些文件描述符以及如何使用。为了利用这一点,POSIX shell 可以打开一个文件并将该文件分配给具有exec
内置描述符的描述符。之后,shell 将启动使用该描述符和文件的程序。
这样做的原因之一是,如果程序想要拥有多个输出或输入文件,并且不想将它们指定为命令行参数。如果只有一个文件,您可以重定向一个标准文件描述符。
我从未见过一个普遍可用的程序会在其手册中宣传这样的事情。这在实践中会发生吗?有人听说过这样的事情吗?
是的,我确实想留在 POSIX 世界中 - 所以没有 bash-only 内置插件。我只是想知道是否有这样的程序,而不是内置的shell。
答案1
当您使用<(...)
or进行进程替换>(...)
时,bash 将在任意高文件描述符上打开一个通向另一个程序的管道(我认为它过去从 10 开始计数,但现在它从 63 开始计数)并按照/dev/fd/N
命令传递名称第一个程序的行。这不是 POSIX,但其他 shell 也支持它(它是 ksh88 功能)。
但这并不完全是您正在运行的程序的功能,它只是查看/dev/fd/N
并尝试像常规文件一样打开它。
Autoconf 手册提到一些历史记录:
一些古老的系统保留了一些文件描述符。按照惯例,
/dev/tty
当您登录到第八版(1985)到第十版 Unix(1989)时,文件描述符 3 被打开。文件描述符 4 在 Stardent/Kubota Titan(大约 1990 年)上有特殊用途,尽管我们现在不记得它是什么。这两个系统都已过时,因此现在可以像对待任何其他文件描述符一样安全地对待文件描述符 3 和 4。另外,当我对此进行谷歌搜索时,我发现了一个名为
runit
使用文件描述符 4 和 5 来实现与日志轮转相关的某些目的。并引用
svlogd
手册页:如果
svlogd
被告知处理最近的日志文件,(...)。svlogd
还保存处理器写入文件描述符 5 的任何输出,并在下一次日志文件轮换时运行处理器时使该输出在文件描述符 4 上可用。
答案2
是的;足够了。
Sato Katsura 提到了 UCSPI,Unix 客户端-服务器程序接口。遵循这一点的程序正常使用标准输入、标准输出和标准错误。但除此之外,该工具集还定义了更多标准打开文件描述符。除了前三个之外,还有其他工具集定义了类似的标准文件描述符。
其中一些甚至彼此一致。就像PC-DOS/DR-DOS/MS-DOS 世界中的标准文件句柄 3 和 4stdaux
一样stdprn
,在某些 Unix 和 UNIX 世界中,文件描述符 3、4、5、6 和 7 实际上有一致的标准用法。 Linux终端管理、日志管理和UCSPI客户端软件。
UCSPI 客户端工具
6 和 7:标准 fromserver 和标准 toserver
对于 UCSPI,人们通常主要记住服务器端协议,其中服务器与其标准输入和输出进行通信。然而,在不太记得的客户端上,诸如tcpclient
(来自 Bernstein 的 UCSPI-TCP)、sslclient
(来自 Baxter's/Gifford's/Hoffman's UCSPI-SSL)和tcp-socket-connect
(来自 nosh 工具集)等工具使用更多标准文件描述符。它们都链接到的客户端程序被定义为期望打开文件描述符 6 来从网络读取,打开文件描述符 7 写入网络。
Bernstein 最初的 ucspi-tcp 工具集附带了一堆围绕tcpclient
.例如:这是伯恩斯坦的简单http@
工具。 (菲利克斯·冯·莱特纳在十多年前发表了一篇更复杂的文章。)
#!/bin/sh echo "GET /${2-} HTTP/1.0 主持人:${1-0}:${3-80} " | tcpclient -RHl0 -- "${1-0}" "${3-80}" sh -c ' 地址>&7 执行delcr <&6 ' | awk '/^$/ { 正文=1;下一个 } { if (body) print }'
进一步阅读
- 乔纳森·德博因·波拉德 (2015)。UNIX 客户端-服务器程序接口上的 gen。经常给出的答案。
- 乔纳森·德博因·波拉德 (2016)。
tcp-socket-connect
。 小吃指南。软件。 - 威廉·巴克斯特(2015)。
sslclient
。 UCSPI-SSL。超级脚本。 s6-tcpclient
。 s6 网络。洛朗·贝尔科特.
终端管理工具
3、4、5:标准ctty、标准PTY主从
Daniel J. Bernstein 的原始 PTY 工具集将额外的标准文件描述符定义合并到工具集中。文件描述符 3 是控制终端(Bernstein 在其有关 shell 中作业控制的随附论文中建议的约定),文件描述符 4 是 PTY 的主端,文件描述符 5 是其从端。
PTY 工具集可能是最极端的工具示例,这些工具在其手册中定义了特定的打开文件描述符约定。 ptyspawn
的手册页讨论了文件描述符 0、1、2、3、4、5 和 9。
nosh 工具集的终端管理工具共享其中一些工具。 pty-get-tty
例如,将其打开的伪终端的主端作为文件描述符 4 传递;并且双方pty-run
都console-terminal-emulator
希望在那里收到它。
进一步阅读
- 乔纳森·德博因·波拉德 (2016)。 ”丹尼尔·J·伯恩斯坦的
ptyget
工具集”。 DJBwares。软件。 - 乔纳森·德博因·波拉德 (2010)。Daniel J. Bernstein 谈 UNIX 中的 TTY。经常给出的答案。
- 乔纳森·德博因·波拉德 (2014)。
pty-get-tty
。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2014)。
pty-run
。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2014)。
console-terminal-emulator
。 小吃指南。软件。
LISTEN_FDS
协议
3 及以上:标准聆听
UCSPI 对于通过考试意味着什么连接的套接字,这个协议是为了传递倾听插座。 (它就在名称中。)inetd
侦听套接字的原始协议是它们是服务器进程的标准输入,而这就是 Bercot 的 s6 网络工具集仍然所做的事情之一。但在 systemd 世界中,这一想法是让服务器进程同时监听多个套接字。因此出现了这个协议,它将文件描述符 3 及以上定义为一系列氮打开文件描述符,其中氮是环境变量的值LISTEN_FDS
。
因此,尽管其手册中可能没有明确说明,但每个包含此协议的服务器程序都有一组它所期望的“标准监听”文件描述符。
不过,诸如 之类的工具的手册页tcp-socket-listen
(它们都采用并添加侦听套接字文件描述符)确实明确提到了这些文件描述符。他们还提到了UPSTART_FDS
来自新贵世界的鲜为人知的协议。
进一步阅读
s6-tcpserver6-socketbinder
。 s6 网络。洛朗·贝尔科特.- 乔纳森·德博因·波拉德 (2014)。
local-datagram-socket-listen
。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2014)。
local-stream-socket-listen
。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2015)。
netlink-datagram-socket-listen
。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2014)。
tcp-socket-listen
。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2014)。
udp-socket-listen
。 小吃指南。软件。 - 乔纳森·德博因·波拉德 (2014)。
fifo-listen
。 小吃指南。软件。
记录工具
4和5:标准旋转数据
正如您已经观察到的,以 Bernstein 开始的约定是在日志轮转时multilog
产生的工具及其后继者的约定。multilog
所有这些都将文件描述符 4 和 5 定义为在旋转过滤器程序的运行之间传递数据的一种方式。
进一步阅读
- 乔纳森·德博因·波拉德 (2015)。 ”记录”。 守护进程工具家族。经常给出的答案。
用户管理工具
3:标准凭证
Bernstein 的checkpassword
接口最初用于验证 POP3 服务器登录,定义了另一套工具,期望打开额外的文件描述符。再次,它是文件描述符 3,预计生成程序已在该文件描述符上写入或正在写入密码检查程序验证的用户帐户凭据。现在有一个完整的checkpassword
兼容程序子系列。
进一步阅读
- 丹尼尔·J·伯恩斯坦。 ”界面
checkpassword
”。 互联网邮件。 cr.yp.to。