Mark Sobell的 Linux命令、编辑器和Shell编程实用指南,第二版他写道(p. 432):
& lt;和令牌复制输入文件描述符;祝辞,重复输出文件描述符。
这似乎与同一页上的另一个语句不一致:
使用以下格式打开或将文件描述符n重定向为a文件描述符m的副本:
exec n<和m>和m>
和一个示例也在同一页上:
# File descriptor 3 duplicates standard input
# File descriptor 4 duplicates standard output
exec 3<&0 4<&1
如果祝辞,复制一个输出文件描述符那么我们不应该说
exec 4>&1
复制标准输出?
这个例子在实践中是正确的。这本书最初的解释是对POSIX标准的准确描述,但是我手边的类POSIX shell (bash
和dash
,我相信在Linux上常见的两个shell)并没有那么挑剔。
POSIX标准与书中关于输入和输出描述符的规定相同,并继续说:对于n<&word
,"如果word
中的数字不代表已经为输入打开的文件描述符,将导致重定向错误"。所以如果你想要小心POSIX兼容性,你应该避免这种用法。
bash文档也对<&
和>&
说了同样的话,但没有承诺会出现错误。这很好,因为它不会给出错误。相反,根据经验,n<&m
和n>&m
似乎是可以互换的。<&
和>&
之间的唯一区别是,如果您在左侧留下fd数字,<&
默认为0 (stdin), >&
默认为1 (stdout)。
例如,让我们启动一个shell,让fd 1指向文件bar
,然后完全尝试exec 4<&1
示例,尝试写入结果fd 4,看看它是否有效:
$ sh -c 'exec 4<&1; echo foo >&4' >bar; cat bar
foo
它可以,这适用于使用dash
或bash
(或bash --posix
)的shell。
在幕后,这是有意义的,因为<&和>,几乎可以肯定的是,我们只是在调用dup2(),它并不关心FDS是否为读、写、追加或其他什么而打开。
[EDIT:在评论中讨论后添加了对POSIX的引用]
如果stdout是tty,则可以安全地克隆它以进行读写。如果stdout是一个文件,那么它可能无法工作。我认为这个例子应该是4>&1
。我同意Greg的观点,即既可以读也可以写克隆描述符,但是用<&
请求重定向应该是用可读的源描述符完成的,而期望标准输出是可读的是没有意义的。(虽然我承认我没有这种说法的参考资料。)
一个例子可以使它更清楚。使用下面的脚本:
#!/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
我得到以下输出(在终端输入"Reading from"行上的:之后的内容):
$ ./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)。