&>是什么在bash做什么?

时间:2014-07-17 00:32:24

标签: bash

我正在查看pre-commit hook并发现了以下行,因为我想知道为什么我在提交后总是在我的目录中有一个名为1的empy文件。

git status 2&>1 > /dev/null

我认为其目的是写下以下内容,并对其进行了更正。

git status 2>&1 > /dev/null

但是,我很好奇以下语法的确切内容,所以我查看了手册页。

git status 2&>1

这是手册页。

  Redirecting Standard Output and Standard Error
      This  construct allows both the standard output (file descriptor 1) and
      the standard error output (file descriptor 2) to be redirected  to  the
      file whose name is the expansion of word.

      There  are  two  formats  for  redirecting standard output and standard
      error:

             &>word
      and
             >&word

      Of the two forms, the first is preferred.  This is semantically equiva‐
      lent to

             >word 2>&1

但是,这个手册页暗示两者是等价的,似乎并非如此。

有人可以澄清手册页并准确解释这种语法会发生什么吗?

2 个答案:

答案 0 :(得分:43)

我们在这里使用的运营商是:

  • >语法: file_descriptor opt > file_name
  • >&语法: file_descriptor opt >& file_descriptor
  • &>语法:&> file_name

如果省略文件描述符,则输入的默认值为0(stdin),输出的默认值为1(stdout)。 2表示stderr。

所以我们有:

  • >name表示1>name - 将stdout重定向到文件name
  • &>name表示1>name 2>name - 将stdout和stderr重定向到文件name

所以当你写git status 2&>1时,它是git status 2 1>1 2>1,即

  • 第一个2实际上作为参数传递给git status
  • stdout被重定向到名为1的文件(不是文件描述符1)
  • stderr被重定向到名为1
  • 的文件

此命令实际上应该创建一个名为1的文件,其内容是git status 2的结果 - 即名为2的文件的状态,可能是"您的分支是最新的,没有提交,工作目录清理",假设您实际上没有跟踪名为2的文件。

答案 1 :(得分:7)

&>word(以及>&wordstdoutstderr重定向到扩展单词的结果。在上述情况下,文件为1

2>&1stderr(fd 2)重定向到当前值stdout(fd 1)。 (在行之后重定向stdout之前执行此不会达到您的预期效果,并且会将输出拆分而不是将它们组合在一起,这是一个非常常见的shell脚本错误。 >word 2>&1将两个fds组合成一个发送到同一位置的文件。)

$ { echo stdout; echo stderr >&2; }
stdout
stderr
$ { echo stdout; echo stderr >&2; } >/dev/null
stderr
$ { echo stdout; echo stderr >&2; } >/dev/null 2>&1
$ 
{ echo stdout; echo stderr >&2; } 2>&1 >/dev/null
stderr

不是那些,虽然看起来相似,但不是一回事。

事实上,

git status 2&>1 > /dev/null实际上正在运行git status 2,并将&>1stdoutstderr重定向到文件1)。几乎肯定不是故意的。你的修正几乎肯定是预期的。

$ git init repro
Initialized empty Git repository in /tmp/repro/.git/
$ cd repro/
$ git status
# On branch master
#
# Initial commit
#
nothing to commit
$ ls
$ git status 2>&1
# On branch master
#
# Initial commit
#
nothing to commit
$ ls
$ git status 2&>1
$ ls
1
$ cat 1
# On branch master
#
# Initial commit
#
nothing to commit