在 Unix shell 中,如果我想组合 stderrstdout 进入 stdout 为了进一步操作,我可以在命令末尾附加以下内容:

2>&1

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

g++ lots_of_errors 2>&1 | head

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

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

有人可以打破这个并逐个字符地解释什么吗 2>&1 方法?

有帮助吗?

解决方案

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

以下是记住此构造的一种方法(虽然它并不完全准确):首先, 2&gt; 1 可能看起来像是将 stderr 重定向到的好方法<代码>标准输出。但是,它实际上将被解释为“重定向 stderr 到名为 1 ”的文件。 &amp; 表示后面是文件描述符而不是文件名。因此构造变为: 2&gt;&amp; 1

其他提示

echo test > afile.txt

将stdout重定向到 afile.txt 。这与做

相同
echo test 1> afile.txt

要重定向stderr,请执行以下操作:

echo test 2> afile.txt

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

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

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

反之亦然:

echo test 2>&1

因此,简而言之...... 2&gt; 将stderr重定向到(未指定的)文件,附加&amp; 1 将stderr重定向到stdout。

关于重定向的一些技巧

有关于此的一些语法特殊性可能具有重要的行为。有一些关于重定向的小示例, STDERR, STDOUT, ,和参数 订购.

1 - 覆盖还是追加?

象征 > 意思是 重定向.

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

无论如何,如果文件不存在,就会创建该文件。

2 - 的 外壳命令行 取决于订单!

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

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

附录:注意! 随着新版本的 (>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

附录:注意! 两种方式都相同的新语法:

$ 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

为了这 特别的 情况下,有一个快捷语法: &> ...或者 >&

$ 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

在一个 安慰 ;-)

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

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

  

$ command&amp;&gt; file

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

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

如您所见,stdout和stderr现在都指向 file 。因此,写入stdout和stderr的任何内容都会写入 file

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

  

$ command&gt; file 2&gt;&amp; 1

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

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

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

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

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

但是要小心!写

  

命令&gt;文件2&gt;&amp; 1

与写作不同:

  

$ command 2&gt;&amp; 1&gt; file

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

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

现在Bash看到第二个重定向,&gt;文件,它将stdout重定向到file:

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

也没有

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

该构造将标准错误流( 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

这允许一些相当复杂的技巧。

2&gt;&amp; 1 是POSIX shell构造。以下是按令牌分类的令牌:


2 :&quot; 标准错误&quot;输出文件描述符。

&gt;&amp; 复制输出文件描述符 运算符( 输出重定向 运算符&gt; )。给定 [x]&gt;&amp; [y] ,将 x 表示的文件描述符作为输出文件描述符 y

1 &quot; 标准输出&quot;输出文件描述符。

表达式 2&gt;&amp; 1 将文件描述符 1 复制到位置 2 ,因此任何输出都写入 2 (“标准错误”)转到最初由 1 (“标准输出”)描述的相同文件。


进一步解释:

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

标准输出/错误:请参阅重定向部分:

  

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

2是控制台标准错误。

1是控制台标准输出。

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

E.g。当你运行

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。

我建议你试着理解这些。

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

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

为了帮助你记住

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

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

我也推荐阅读 这篇关于错误重定向的文章 其中详细介绍了该主题。

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

dup2(1, 2);

请参阅手册页

了解 2&gt;&amp; 1 副本也解释了原因......

command >file 2>&1

......与......不一样。

command 2>&1 >file

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

人们,永远记住 帕克斯迪亚布罗的提示 当前的 重定向目标的位置...它 重要的。

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

  • 考虑到 & 作为意义 'and' 或者 'add' (该角色是一个 安培-, ,不是吗?)
  • 所以就变成了: '重定向 2 (stderr) 到哪里 1 (标准输出)已经/当前是并且 添加 两条流'.

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

  • 考虑到 & 意义 and 或者 add...(你知道 & 符号了,是吗?)
  • 所以就变成了: '重定向 1 (标准输出)到哪里 2 (stderr) 已经/当前是并且 添加 两条流'.

并永远记住:您必须从右到左“从末尾”读取重定向链(不是 从左到右)。

如果您的系统上不存在 / foo / tmp 会出现&#8230;

$ 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

是简写

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

即, cmd 不是命令:

$cmd 2>filename
cat filename

command not found

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

2>&1

标准错误发送到终端。

  

重定向输入

     

重定向输入会导致名称为的文件   从扩展单词的结果打开文件阅读   描述符n,或标准输入(文件描述符0),如果n是   未指定。

     

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

[n]<word
     

重定向输出

     

输出的重定向导致文件的输出   名称的结果来自要打开以供写作的单词的扩展   文件描述符n,或标准输出(文件描述符1),如果n   未指定。如果文件不存在则创建;如果它   确实存在它被截断为零大小。

     

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

[n]>word
     

移动文件描述符

     

重定向运算符

[n]<&digit-
     

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

     

类似地,重定向运算符

[n]>&digit-
     

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

价:

man bash

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

在线版本在此处: 3.6重定向

PS:

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

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

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

scroll top