在 >&N 中,为什么 N 被视为文件描述符而不是文件名(正如手册似乎所说的那样)?

Bin*_*rus 5 bash io-redirection

我正在努力理解 bash 中的 IO 重定向。我见过很多像下面这样的例子(这实际上取自此处接受的答案):

exec 3<> /tmp/foo  #open fd 3.
echo "test" >&3
exec 3>&- #close fd 3.
Run Code Online (Sandbox Code Playgroud)

我不明白第二行。准确地说,我不明白它的行为是如何符合bash手册的。

显然,在第二行中,>&3应该重定向stdout(可能stderr- 我不知道)到文件描述符 3;其他一切都没有任何意义。

但根据当前的 bash 手册(在撰写本文时),第 3.6.4 节(格式化我的):

此结构允许将标准输出(文件描述符 1)和标准错误输出(文件描述符 2)重定向到名称为单词扩展的文件。 重定向标准输出和标准错误有两种格式:
&>word>&word

[ 然后它解释了第一种格式和第二种格式之间的细微差别,但让我们暂时把它放在一边,因为它对于这个问题并不重要。]

据我了解,这表示>&3重定向stderrstdout到一个名为 的文件,这与重定向(可能)到文件描述符3有很大不同。stdoutstderr3

有人可以解释一下我缺少什么吗?

ter*_*don 16

实际上,正是您搁置的最相关的部分(来自GNU bash 文档):

\n
\n

3.6.4 重定向标准输出和标准错误

\n

此构造允许将标准输出(文件描述符 1)和标准错误输出(文件描述符 2)重定向到名称为单词扩展的文件。

\n

重定向标准输出和标准\n错误有两种格式:

\n
&>word \n
Run Code Online (Sandbox Code Playgroud)\n

\n
>&word \n
Run Code Online (Sandbox Code Playgroud)\n

在这两种形式中,优选第一种。这在语义上等价于

\n
>word 2>&1 \n
Run Code Online (Sandbox Code Playgroud)\n

使用第二种形式时,单词可能不会扩展为数字或 \xe2\x80\x98-\xe2\x80\x99。如果是这样,出于兼容性原因,将应用其他重定向运算符(请参阅下面的复制\n文件描述符)。

\n
\n

最后一点是最重要的一点,所以我将在这里重复一遍:

\n
\n

使用第二种形式时,单词可能不会扩展为数字或 \xe2\x80\x98-\xe2\x80\x99。如果是这样,出于兼容性原因,将应用其他重定向运算符(请参阅下面的复制\n文件描述符)。

\n
\n

因此,如果word扩展为数字 或-,则会触发特殊规则。字符串扩展到自身,因此3可以说是“扩展”,这3意味着根据复制文件描述符部分>&3中描述的规则进行处理:

\n
\n

重定向运算符

\n
[n]<&word \n
Run Code Online (Sandbox Code Playgroud)\n

用于复制输入文件描述符。如果 word 扩展到一位或多位数字,则 n 表示的文件描述符将成为该文件描述符的副本。如果 word 中的数字未指定打开以供输入\n的文件描述符,则会发生重定向错误。如果 word\n 的值为 \xe2\x80\x98-\xe2\x80\x99,则文件描述符 n 被关闭。如果未指定 n,则使用标准输入(文件描述符 0)。

\n

运营商

\n
[n]>&word \n
Run Code Online (Sandbox Code Playgroud)\n

其用法与复制输出文件描述符类似。如果未指定 n\n,则使用标准输出(文件描述符 1)。如果 word 中的数字未指定为输出而打开的文件描述符,则会发生重定向错误。如果 word 的计算结果为 \xe2\x80\x98-\xe2\x80\x99,则文件描述符 n\nis 已关闭。作为一种特殊情况,如果省略 n,并且 word 不扩展为一位或多位数字或 \xe2\x80\x98-\xe2\x80\x99,则标准输出和标准\n错误将按前面所述进行重定向。

\n
\n

所有这些都是说,在特定情况下,后面跟着的>&是数字,该数字被假定为文件描述符。据推测,这正是手册中明确&>word指出优于同类产品>&word的原因&>word

\n

  • @Binarus,如果我没记错的话,“重定向 stdout 和 stderr”意义上的 `&gt;&amp;` 来自 csh,而 `&gt;&amp;-` 和 `&gt;&amp;NN` 可能来自其他类似 Bourne 的 shell(也许是ksh),而且它们确实有点冲突。后者在 POSIX 中进行了编码(通常它们更有用,并且可以用来组成其他含义),因此 Bash 必须优先考虑它们。我不确定 `&amp;&gt;`,它可能只是 Bash 特有的简写形式,因为它不会与其他简写形式直接冲突。(这意味着不同的东西,但几乎没有用其他外壳) (3认同)