exec n <m与exec n>&m – 基于Sobell的Linux书

在Mark Sobell的“Linux命令,编辑器和Shell编程实用指南”第二版中,他写道(第432页):

<&token复制一个input文件描述符; >&复制输出文件描述符。

这似乎与在同一页上的另一个声明不一致:

使用以下格式打开或redirect文件描述符n作为文件描述符m的副本:

exec n <&m

并在同一页面上举例说明:

# File descriptor 3 duplicates standard input # File descriptor 4 duplicates standard output exec 3<&0 4<&1 

如果&复制输出文件描述符,那么我们不应该说

 exec 4>&1 

重复标准输出?

这个例子在实践中是正确的。 这本书的原始解释是对POSIX标准所描述的内容的准确描述,但是POSIX类似的shell(我认为在Linux上常见的只有bashdash )是不太挑剔的。

POSIX标准与输入和输出描述符的内容是一样的,并继续说:对于n<&word ,“如果word的数字不代表已经打开的文件描述符输入,则会导致重定向错误”。 所以如果你想要小心POSIX的兼容性,你应该避免这种用法。

bash文档也对<&>& 说了同样的事情 ,但没有承诺错误。 这很好,因为它实际上并没有给出错误。 相反,经验上n<&m n>&m似乎是可以互换的。 <&>&的唯一区别在于,如果您离开左侧的fd号码, <&默认为0(stdin), >&为1(stdout)。

例如,让我们用fd 1指向一个文件bar启动一个shell,然后尝试使用exec 4<&1例子,尝试写入结果fd 4,看它是否工作:

 $ sh -c 'exec 4<&1; echo foo >&4' >bar; cat bar foo 

它的确如此,而且这可以使用dashbash (或bash --posix )作为shell。

在引擎盖下,这是有道理的,因为<&和>&几乎可以肯定只是调用dup2() ,它不关心是否打开读取或写入或追加或fds是什么。

[ 编辑 :在评论讨论后增加了对POSIX的参考。]

如果stdout是一个tty,那么它可以安全地被克隆用于读或写。 如果stdout是一个文件,那么它可能无法正常工作。 我认为这个例子应该是4>&1 。 我同意Greg的观点,你既可以读取也可以写入克隆描述符,但是要求用<&来重定向,并且应该使用可读的源描述符来完成,并且希望stdout是可读的,这是没有意义的。 (虽然我承认我没有这个说法的参考。)

一个例子可能会更清楚。 用这个脚本:

 #!/bin/bash exec 3<&0 exec 4<&1 read -p "Reading from fd 3: " <&3 echo From fd 3: $REPLY >&2 REPLY= read -p "Reading from fd 4: " <&4 echo From fd 4: $REPLY >&2 echo To fd 3 >&3 echo To fd 4 >&4 

我得到了下面的输出(后面的内容:在“读取”行输入终端):

 $ ./5878384b.sh Reading from fd 3: foo From fd 3: foo Reading from fd 4: bar From fd 4: bar To fd 3 To fd 4 $ ./5878384b.sh < /dev/null From fd 3: Reading from fd 4: foo From fd 4: foo ./5878384b.sh: line 12: echo: write error: Bad file descriptor To fd 4 $ ./5878384b.sh > /dev/null Reading from fd 3: foo From fd 3: foo ./5878384b.sh: line 9: read: read error: 0: Bad file descriptor From fd 4: To fd 3 

注意文件描述符和IO流之间的区别,如stderr和stdout。

重定向操作符只是通过不同的文件描述符(IO流处理机制)重定向IO流。 他们不做任何IO流的复制或复制(这是tee(1)的用途)。

请参阅: 文件描述符101

另一个显示n <&m和n>&m是否可互换的测试将是“使用n <& – ”或“n>& – ”的任何一种样式来关闭文件描述符,即使它与读取/写入模式下,文件描述符打开“(http://www.gnu.org/s/hello/manual/autoconf/File-Descriptors.html)&#x3002;