IT-Swarm.Net

在壳牌中,“2>&1”是什么意思?

在Unix Shell中,如果我想将stderrstdout组合到stdout流中以进行进一步操作,我可以在命令的末尾附加以下内容:

2>&1

所以,如果我想在g++的输出上使用head,我可以这样做:

g++ lots_of_errors 2>&1 | head

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

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

有人可以打破这个并按字符解释2>&1的含义吗?

1980
Tristan Havelick

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

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

2193
Ayman Hourieh
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。

553
dbr

关于重定向的一些技巧

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

1 - 覆盖或追加?

符号>表示重定向

  • >表示发送给整个已完成的文件,覆盖目标(如果存在)(请参阅#3 _后面的noclobber bash功能)。
  • >> mean (另外发送将附加到目标(如果存在)。

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

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

Nota:&9描述符会因) 9>&2而自发发生。

附录:nota! 使用新版本的 bash>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为 not 覆盖任何现有文件,但>|语法允许您通过此限制:

$ 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 - 最后一招和更多......

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

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

对于这个特殊 case,有一个快捷语法:&> ...或>&

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

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

注意:if2>&1exists,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

bash console ;-)

291
F. Hauri

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

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

$ 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重定向到file:

Enter image description here

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

还要注意在Bash中写作

$ command&> file

与以下内容完全相同:

$ command>&file

79
Deen John

数字指的是文件描述符(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工具,因此除非将其重定向到文件或其他内容,否则不会看到它。

77
Colin Burnett

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

您可以使用此方法将任何输出句柄重定向到另一个输出句柄,但它最常用于将stdoutstderr流引导到单个流中进行处理。

一些例子是:

# 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

请注意,最后一个将not direct stderroutfile2 - 它会将其重定向到遇到参数时的stdoutoutfile1)和thenstdout重定向到outfile2

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

54
paxdiablo

2>&1是POSIX Shell构造。这是按令牌分类的令牌:


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

>&复制输出文件描述符 operator( 输出重定向 operator >的变体)。给定[x]>&[y]x表示的文件描述符将成为输出文件描述符y的副本。

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

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


进一步说明:

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

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

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

17
wjordan

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。

我建议你试着去理解这些。

17
Marcus Thornton

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

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

为了帮助你记住

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

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

我还建议阅读 这篇关于错误重定向的帖子 详细介绍了这个主题。

16
Andrioid

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

dup2(1, 2);

请参阅 手册页

理解2>&1 copy 也解释了为什么......

command >file 2>&1

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

command 2>&1 >file

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

11
ams

如果您的系统上不存在/foo/tmp ...

$ ls -l /tmp /foo

将打印/tmp的内容并打印/foo的错误消息

$ ls -l /tmp /foo > /dev/null

/tmp的内容发送到/dev/null并打印/foo的错误消息

$ ls -l /tmp /foo 1> /dev/null

将完全相同(注意 1

$ ls -l /tmp /foo 2> /dev/null

将打印/tmp的内容并将错误消息发送到/dev/null

$ ls -l /tmp /foo 1> /dev/null 2> /dev/null

将发送列表以及错误消息发送到/dev/null

$ ls -l /tmp /foo > /dev/null 2> &1

是简写

6
Matijs

人们总是记得 paxdiablo 暗示重定向目标的 当前 位置......它重要的。

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

  • &想象成'and''add'(字符是 ampers - ,不是吗?)
  • 所以它变为: '重定向2(stderr)到1(stdout)已经/当前是和 添加 两个流'

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

  • 想想&意思是andadd...(你明白了&符号,是吗?)
  • 所以它变为: '重定向1(stdout)到2(stderr)已经/当前是和 添加 两个流'

永远记住:你必须从右到左阅读重定向链(从左到右)。

6
Kurt Pfeifle

这就像将错误传递给stdout或终端一样。

也就是说,cmd不是命令:

$cmd 2>filename
cat filename

command not found

错误发送到文件,如下所示:

2>&1

标准错误发送到终端。

5
Kalanidhi

重定向输入

输入的重定向导致打开名称由Word扩展产生的文件,以便在文件描述符n上读取,或者如果未指定n,则打开标准输入(文件描述符0)。

重定向输入的一般格式是:

[n]<Word

重定向输出

输出的重定向导致打开名称来自Word扩展的文件,以便在文件描述符n上写入,或者如果未指定n,则打开标准输出(文件描述符1)。如果文件不存在则创建;如果确实存在则将其截断为零大小。

重定向输出的一般格式是:

[n]>Word

移动文件描述符

重定向运算符,

[n]<&digit-

如果未指定n,则将文件描述符数字移动到文件描述符n,或标准输入(文件描述符0)。数字在复制到n后关闭。

同样,重定向运算符

[n]>&digit-

如果未指定n,则将文件描述符数字移动到文件描述符n或标准输出(文件描述符1)。

参考:

man bash

键入/^REDIRECT以找到redirection部分,并了解更多...

在线版本在这里:3.6重定向

PS:

很多时候,man是学习Linux的强大工具。

4
yurenchen

0表示输入,1表示stdout,2表示stderr。

一个提示 somecmd >1.txt 2>&1是正确的,而somecmd 2>&1 >1.txt完全 错误 没有效果!

1
fzyzcjy