题 在shell中,“2>&1”是什么意思?


在Unix shell中,如果我想要组合 stderr 和 stdout 进入 stdout 流进行进一步操作,我可以在命令的末尾添加以下内容:

2>&1

所以,如果我想使用 head 关于输出 g++,我可以这样做:

g++ lots_of_errors 2>&1 | head

所以我只能看到前几个错误。

我总是很难记住这一点,而且我不得不去查找它,主要是因为我不完全理解这个特殊技巧的语法。

有人可以解决这个问题并逐字解释 2>&1  手段?


1738
2018-05-03 22:57


起源


@dbr我不认为这只是bash - 我相信这是一个bourne shell的事情;因此sh,bash,ksh,ash,dash等 - guns
这是描述POSIX兼容shell的重定向段落的一部分,简称POSIX shell。例如,ksh是一个POSIX shell。看到:pubs.opengroup.org/onlinepubs/009695399/utilities/... - jim mcnamara
此构造也适用于Windows。 - Vadzim
通常做得更好 2>&1 比 2>的/ dev / null的 ;-) - F. Hauri
我以为我会提到这一点 |&  是简写 2>&1 | 如果你使用zsh。我不能说这是否适用于其他类似bourne的shell或者它是否仅仅是zsh功能。 - chrixian


答案:


文件描述符1是标准输出(stdout)。
文件描述符2是标准错误(stderr)。

这是一种记住这种结构的方法(尽管它并不完全准确):起初, 2>1 可能看起来像是重定向的好方法 stderr 至 stdout。但是,它实际上将被解释为“重定向” stderr 到一个名为的文件 1”。 & 表示后面是文件描述符而不是文件名。所以构造变成: 2>&1


1943
2018-05-03 23:04



但那不应该是 &2>&1? - dokaspar
@Dominik:不, & 仅被解释为在重定向的上下文中表示“文件描述符”。写作 command &2>& 被解析为 command & 和 2>&1,即“跑 command 在后台运行命令 2 并将其标准输出重定向到其标准输出“。 - Adam Rosenfield
这里有趣的信息: mywiki.wooledge.org/BashFAQ/055 - Halil Özgür
但是,如何将stderr重定向到名为“&1”的文件? - Martín Fixman
@马丁: 2>'&1' - rogual


echo test > afile.txt

将stdout重定向到 afile.txt。这和做的一样

echo test 1> afile.txt

要重定向stderr,您可以:

echo test 2> afile.txt

>& 是将流重定向到另一个文件描述符的语法 - 0是stdin,1是stdout,2是stderr。

您可以通过执行以下操作将stdout重定向到stderr:

echo test 1>&2 # or echo test >&2

或相反亦然:

echo test 2>&1

所以,简而言之...... 2> 将stderr重定向到(未指定的)文件,追加 &1 将stderr重定向到stdout。


481
2018-05-03 22:59



这对你有意义吗 java ... 2&1 >> data.log,我看到我的一位同事这样做了? - Thang Pham
@Harry看起来像是一个不是bash的shell,或者是一个错字。 cmd 2>&1 >> somefile.log 将stdout / stderr附加到文件 - 它与上面的基本相同,有 >> file 追加 - dbr
@dbr cmd 2>&1 >>file 不会将stderr重定向到该文件,但是 cmd >> file 2>&1 确实。订单很重要。在第一种情况下,stderr被重定向到shell的stdout(如果以交互方式输入命令,则可能是tty),然后将stdout定向到该文件。在第二种情况下,stdout被定向到文件,然后stderr被定向到同一个地方。 - William Pursell
我喜欢上面的答案,但它可能更清晰。 “2>&1”将stderr重定向到stdout的目标。所以,如果你有类似“ls -l >> directoryContents 2>&1”的结果,结果将是一个名为directoryContents的文件,它将附加工作目录的内容。如果执行中有任何错误:错误消息也会在发生时附加到directoryContents文件中。 - Max West
是 0(or 1,2)>&0(or 1,2) 像一个控制输出的选项?是 echo test >test.log 2>&1 与...一样 echo test 2>&1 >test.log? - Simin Jie


关于重定向的一些技巧

关于此的一些语法特殊性可能具有重要的行为。有一些关于重定向的小样本, STDERRSTDOUT和论点 排序

1 - 覆盖或追加?

符号 > 意思 重定向

  • > 意思 发送到整个完整的文件,如果存在则覆盖目标(见 noclobber bash功能 #3 后来)。
  • >> 意思 发送除了 如果存在,将附加到目标。

在任何情况下,如果文件不存在,将创建该文件。

2 - shell命令行 是订单依赖!!

为了测试这个,我们需要 一个简单的命令,它将在两个输出上发送一些东西

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(期望您没有名为的目录 /tnt, 当然 ;)。好吧,我们拥有它!

所以,让我们看看:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

最后一个命令行转储 STDERR 到控制台,它似乎不是预期的行为......但......

如果你想做一些 过滤后 关于一个输出,另一个或两个:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

请注意,本段中的最后一个命令行与我写的前一段中的完全相同 似乎不是预期的行为 (所以,这甚至可能是预期的行为)。

嗯,有一些关于重定向的技巧 对两个输出进行不同的操作

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

诺塔: &9描述符会自发地发生,因为 ) 9>&2

附录:nota! 随着新版本  (>4.0)有一个新功能和更性感的语法来做这种事情:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

最后对于这样的级联输出格式:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

附录:nota! 两种方式都有相同的新语法:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

哪里 STDOUT 通过一个特定的过滤器, STDERR 到另一个,最后两个输出合并通过第三个命令过滤器。

3 - 关于 noclobber 选项和 >| 句法

那就是 覆盖

set -o noclobber 指示bash  覆盖任何现有文件, >| 语法允许您通过此限制:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

每次都会覆盖该文件,现在好了:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

通过 >|

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

取消设置此选项和/或询问是否已设置。

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - 最后一招和更多......

用于重定向  从给定命令输出,我们看到正确的语法可能是:

$ ls -ld /tmp /tnt >/dev/null 2>&1

为了这 特别 case,有一个快捷语法: &> ... 要么 >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

诺娜:如果 2>&1 存在, 1>&2 也是一个正确的语法:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b-现在,我会让你考虑一下:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c-如果你有兴趣的话 更多 信息

您可以通过点击阅读精细手册:

man -Len -Pless\ +/^REDIRECTION bash

在一个  安慰 ;-)


257
2018-04-29 16:33



进一步阅读: 如果你喜欢这个,你可能会赞成: 重定向滥用如何导致奇怪的行为 - F. Hauri
进一步阅读||: 一个 函数将两个输出存储到分离的变量中 - F. Hauri


数字指的是文件描述符(fd)。

  • 零是 stdin 
  • 一个是 stdout 
  • 二是 stderr

2>&1 将fd 2重定向到1。

如果程序使用它,这适用于任意数量的文件描述符。

你可以看看 /usr/include/unistd.h 如果你忘了他们:

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

这就是说我编写了使用非标准文件描述符进行自定义日志记录的C工具,因此除非将其重定向到文件或其他内容,否则不会看到它。


67
2018-05-03 22:58





该构造发送标准错误流(stderr)到 当前 标准输出的位置(stdout) - 这个货币问题似乎被其他答案所忽略。

您可以使用此方法将任何输出句柄重定向到另一个输出句柄,但它最常用于通道 stdout 和 stderr 流成单个流进行处理。

一些例子是:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

请注意,最后一个会  直接 stderr 至 outfile2  - 它将其重定向到什么 stdout 是在遇到这个论点时(outfile1)和 然后 重定向 stdout 至 outfile2

这允许一些非常复杂的技巧。


49
2018-05-03 23:54



虽然最后一个例子会更加清晰:foo> outfile2 2> outfile1 - Michael Cramer
更清楚,是的,但这不会显示重定向的“位置”性质。这个例子是设计的,因为在一行中执行此操作通常不常用 - 当不同的各方负责重定向的不同部分时,该方法变得非常有用。例如,当脚本执行一点重定向并且您使用另一位运行它时。 - paxdiablo
我刚刚意识到最后一个例子也解决了我为什么这样做的长期困惑: some_program 2>&1 > /dev/null 不是这样的: some_program > /dev/null 2>&1。 - snapfractalpop
你对最后一个例子的评论值得用金字母:-)我从没想过这些重定向的论点是位置的......我认为这一点非常重要。 - Nils-o-mat


我在重定向上发现了这篇精彩的帖子: 所有关于重定向

将标准输出和标准错误重定向到文件

$ command&> file

这个单线使用了 &> 运算符将两个输出流(stdout和stderr)从命令重定向到文件。这是Bash快速将两个流重定向到同一目的地的快捷方式。

以下是Bash重定向两个流后文件描述符表的样子:

Enter image description here

正如你所看到的,stdout和stderr现在都指向了 file。因此写入stdout和stderr的任何内容都会被写入 file

有两种方法可以将两个流重定向到同一目标。您可以一个接一个地重定向每个流:

$ command> file 2>&1

这是将两个流重定向到文件的更常见方法。第一个stdout被重定向到文件,然后stderr被复制到与stdout相同。所以这两个流最终都指向了 file

当Bash看到几个重定向时,它会从左到右处理它们。让我们完成这些步骤,看看会发生什么。在运行任何命令之前,Bash的文件描述符表如下所示:

Enter image description here

现在Bash处理第一个重定向>文件。我们之前已经看过这个,它使stdout指向文件:

Enter image description here

下一个Bash看到第二个重定向2>&1。我们之前没有见过这种重定向。这个复制文件描述符2是文件描述符1的副本,我们得到:

Enter image description here

两个流都已重定向到文件。

不过要小心!写作

命令>文件2>&1

与写作不同:

$ command 2>&1>文件

重定向的顺序在Bash中很重要!此命令仅将标准输出重定向到文件。 stderr仍会打印到终端。要理解为什么会发生这种情况,让我们再次讨论这些步骤。所以在运行命令之前,文件描述符表如下所示:

Enter image description here

现在Bash处理从左到右的重定向。它首先看到2>&1所以它将stderr复制到stdout。文件描述符表变为:

Enter image description here

现在Bash看到了第二个重定向, >file,它将stdout重定向到文件:

Enter image description here

你看到这里发生了什么? Stdout现在指向文件,但是stderr仍然指向终端!写入stderr的所有内容仍会打印到屏幕上!所以要非常非常小心重定向的顺序!

还要注意在Bash中写作

$ command&> file

与以下内容完全相同:

$ command>&file


47
2017-10-29 13:04



如果“command”以数字结尾,则后两个是不同的,因为那时它被视为可选的文件描述符 >& - M.M
精彩的解释!谢谢 - Vicer


2>&1 是一个POSIX shell结构。以下是按令牌分类的令牌:


2:“标准错误“输出文件描述符。

>&复制输出文件描述符 运算符(。的变体) 输出重定向 操作者 >)。特定 [x]>&[y],表示的文件描述符 x 使其成为输出文件描述符的副本 y

1 “标准输出“输出文件描述符。

表达方式 2>&1 复制文件描述符 1 到位置 2,所以写入的任何输出 2 执行环境中的(“标准错误”)转到最初描述的同一文件 1 (“标准输出”)。


进一步说明:

文件描述符:“每个进程唯一的非负整数,用于标识用于文件访问的打开文件。”

标准输出/错误:请参阅以下注释 重定向 shell文档的一部分:

打开文件由以零开头的十进制数表示。最大可能的值是实现定义的;但是,所有实现都应支持至少0到9(包括0和9),以供应用程序使用。这些数字称为“文件描述符”。值0,1和2具有特殊含义和常规用途,并且由某些重定向操作暗示;它们分别称为标准输入,标准输出和标准误差。程序通常从标准输入中获取输入,并在标准输出上写入输出。错误消息通常写在标准错误上。重定向运算符可以在一个或多个数字之前(不允许插入字符)来指定文件描述符号。


13
2017-12-25 06:43





回答你的问题:它需要任何错误输出(通常发送到stderr)并将其写入标准输出(stdout)。

当您需要对所有输出进行分页时,这有助于例如“更多”。有些程序喜欢将使用信息打印到stderr中。

帮助你记住

  • 1 =标准输出(程序打印正常输出)
  • 2 =标准错误(程序打印错误)

“2>&1”只是将发送到stderr的所有内容指向stdout。

我也建议阅读 关于错误重定向的这篇文章 详细介绍了这一主题。


12
2018-05-03 23:24





2是控制台标准错误。

1是控制台标准输出。

这是标准的Unix,Windows也遵循POSIX。

例如。当你跑步

perl test.pl 2>&1

标准错误被重定向到标准输出,因此您可以同时看到两个输出:

perl test.pl > debug.log 2>&1

执行后,您可以在debug.log中查看所有输出,包括错误。

perl test.pl 1>out.log 2>err.log

然后标准输出转到out.log,标准错误转到err.log。

我建议你试着理解这些。


12
2017-07-19 03:23



第二个样本是错误的:作为订单优先顺序 STDERR 被重定向到 STDOUT,只有默认值 STDOUT 将被写入 的debug.log (不 STDERR见 我的答案 (第2段)!确保 都 要重定向到同一文件,您必须反转重定向指令: perl test.pl > debug.log 2>&1 - F. Hauri


从程序员的角度来看,它恰恰意味着:

dup2(1, 2);

手册页

理解这一点 2>&1 是一个 复制 也解释了原因......

command >file 2>&1

......和...不一样

command 2>&1 >file

第一个将两个流发送到 file,而第二个将发送错误 stdout,和普通输出 file


10
2017-12-03 10:20





人们永远记得 paxdiablo关于这个问题的暗示 当前 重定向目标的位置......它  重要。

我个人的助记符 2>&1 运营商是这样的:

  • 考虑到 & 作为意义 'and' 要么 'add' (角色是 ampers - ,不是吗?)
  • 所以它变成了: “重定向 2 (stderr)去哪里 1 (stdout)已经/目前是和  两个溪流'

同样的助记符也适用于其他常用的重定向, 1>&2

  • 考虑到 & 含义 and 要么 add...(你明白了&符号,是吗?)
  • 所以它变成了: “重定向 1 (stdout)去哪里 2 (stderr)已经/目前是和  两个溪流'

并且永远记住:你必须从右到左阅读“从末尾”重定向链( 从左到右)。


4
2017-07-01 10:47