【问题标题】:What does &> do in bash?&> 在 bash 中有什么作用?
【发布时间】:2014-09-07 16:57:40
【问题描述】:

我正在查看 pre-commit 钩子并发现以下行,因为我想知道为什么在提交后我的目录中总是有一个名为 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

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

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

【问题讨论】:

  • 我以为我在某个地方看到了这个问题......也许我错了。
  • 符号顺序不同。
  • @devnull,我知道这是一个错字,但我还是想知道它是什么意思。 :)
  • &>2>&1 相同在 bash 中,但在其他 shell 中不一样,例如 dash!
  • 投票重新打开 - 副本不同(并且git status 2>&1git status 2&>1 不同)

标签: bash


【解决方案1】:

我们在这里使用的运算符是:

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

如果省略文件描述符,则默认为0 (stdin) 用于输入,或1 (stdout) 用于输出。 2 表示标准错误。

所以我们有:

  • >name 表示 1>name -- 将标准输出重定向到文件 name
  • &>name 就像 1>name 2>name -- 将 stdout 和 stderr 重定向到文件 name (但是 name 只打开一次;如果你真的写了 1>name 2>name 它会尝试打开 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 的文件。

【讨论】:

  • 你好,我认为&> name不等同于1>name 2>name,它等同于1>name 2>&1。请参阅man bash中的“重定向标准输出和标准错误”部分
  • @yundongxu 您链接到的页面(问题中也引用了该页面)说 &>name>name 2>&1 相同。这与1>name 2>&1 相同,因为> 运算符是这样定义的。我不确定你想说什么。
  • 在您的回答中,您说“&>name 表示1>name 2>name”。但我认为1>name 2>name1>name 1>&2 不一样。我写了一个小脚本来证明,大家可以查看here
  • @yundongxu 我从来没有声称1>name 1>&2 是一样的。我唯一的主张是2&>1 表示2 1>1 2>1,其中第一个2 是命令的参数。在您的测试脚本中,将git status 2&>1git status 2 1>1 2>1 进行比较。
  • 迟到了,但供以后的读者参考:&>file 相当于1>file 2>&1。执行1>file 2>file 将不起作用,因为文件在不同的文件描述符下打开了两次。文件中的文本将是混乱的(并且不是真正确定的)。要以可移植的方式重定向 STDOUT 和 STDERR,请使用 >file 2>&1(另外,顺序很重要,因此 OP 建议的命令只会将错误重定向到文件并将标准输出重定向到 /dev/null)
【解决方案2】:

&>word(和>&wordstdoutstderr 都重定向到word 扩展的结果。在上述情况下是文件1

2>&1stderr (fd 2) 重定向到stdout (fd 1) 的当前值。 (这样做before 重定向stdout 后面的行不会做你所期望的,并且会拆分输出而不是保持它们组合,这是一个非常常见的shell脚本错误。对比@987654330 @ 将两个 fd 合并为一个发送到同一位置。)

$ { 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

【讨论】:

  • 回复。排序的事情,我的想法是A >& B重定向A指向B当前指向的地方——它不会重定向A的行到成为B 或类似内容的输入行。在 C 语言中,就像在 FILE * 上做 =
猜你喜欢
  • 2016-09-10
  • 1970-01-01
  • 2020-05-20
  • 1970-01-01
  • 2014-01-24
  • 2011-06-02
  • 2018-01-24
  • 1970-01-01
  • 2018-11-19
相关资源
最近更新 更多