“2>1”是什么意思?

要将stderrstdout合并到stdout流中,我们将其附加到命令中:

2>&1

例如,查看编译g++ main.cpp的前几个错误:

g++ main.cpp 2>&1 | head

2>&1具体是什么意思?

1572919 次浏览

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

将stdout重定向到file.txt

echo test > file.txt

这相当于:

echo test 1> file.txt

将stderr重定向到file.txt

echo test 2> file.txt

所以>&重定向到另一个文件描述符的语法:

  • 0是标准输入
  • 1是标准输出
  • 2是标准

将stdout重定向到stderr:

echo test 1>&2   # equivalently, echo test >&2

将stderr重定向到stdout:

echo test 2>&1

2>&1中:

  • 2>将stderr重定向到(未指定的)文件。
  • &1将stderr重定向到stdout。

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

起初,2>1看起来像是将stderr重定向到stdout的好方法。然而,它实际上会被解释为“将stderr重定向到名为1的文件”。

&表示后面和前面的是文件描述符,而不是文件名。因此,我们使用2>&1。将>&视为重定向合并运算符。

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

例如,当您需要对所有输出进行分页时,这对'more'很有帮助。有些程序喜欢将使用信息打印到标准错误中。

来帮你回忆

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

“2>&1”简单地指向发送到stderr的所有内容,而是指向stdout。

我还建议阅读这篇关于错误重定向的文章,其中详细介绍了这个主题。

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

请注意,最后一个将没有定向stderroutfile2-它将其重定向到遇到参数时的stdoutoutfile1),然后stdout重定向到outfile2

这允许一些相当复杂的诡计。

人们,永远记住paxdiablo关于重定向目标当前位置的提示……它很重要。

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

  • &想象成'and''add'(字符是安培-,不是吗?)
  • 所以它变成了:'重定向#0(stderr)到#1(stdout)已经/当前所在的位置,并添加两个流'

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

  • 想想&意味着andadd……(你明白关于&符号的想法,对吗?)
  • 所以它变成了:'重定向#0(stdout)到#1(stderr)已经/当前所在的位置,并添加两个流'

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

关于重定向的一些技巧

关于这一点的一些语法特殊性可能具有重要的行为。有一些关于重定向、STDERRSTDOUT和参数订购的小样本。

1-覆盖或附加?

符号>表示重定向

  • >表示作为一个完整的文件发送,如果存在则覆盖目标(请参阅后面#3处的noclobber bash功能)。
  • >>表示除了发送将附加到目标(如果存在)。

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

2-shell命令行依赖于顺序!!

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

$ ls -ld /tmp /tntls: cannot access /tnt: No such file or directorydrwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp
$ ls -ld /tmp /tnt >/dev/nullls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt 2>/dev/nulldrwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(当然,你没有一个名为/tnt的目录;)。好吧,我们有它!!

所以,让我们看看:

$ ls -ld /tmp /tnt >/dev/nullls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt >/dev/null 2>&1
$ ls -ld /tmp /tnt 2>&1 >/dev/nullls: 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 /tmpE: 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 /tmpE: 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 -n1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp2  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 /tmp2  E: ls: cannot access /tnt: No such file or directory

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

2b-使用|&代替

语法command |& ...可以用作command 2>&1 | ...别名。关于命令行顺序的相同规则适用。更多详细信息在bash中操作符|&的含义是什么?

3-关于noclobber选项和>|语法的一个词

关于覆盖

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

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)
$ date > $testfile ; cat $testfileMon Jan  7 13:18:15 CET 2013
$ date > $testfile ; cat $testfileMon Jan  7 13:18:19 CET 2013
$ date > $testfile ; cat $testfileMon Jan  7 13:18:21 CET 2013

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

$ set -o noclobber
$ date > $testfile ; cat $testfilebash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing fileMon Jan  7 13:18:21 CET 2013
$ date > $testfile ; cat $testfilebash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing fileMon Jan  7 13:18:21 CET 2013

通过>|

$ date >| $testfile ; cat $testfileMon Jan  7 13:18:58 CET 2013
$ date >| $testfile ; cat $testfileMon Jan  7 13:19:01 CET 2013

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

$ set -o | grep noclobbernoclobber           on
$ set +o noclobber
$ set -o | grep noclobbernoclobber           off
$ date > $testfile ; cat $testfileMon 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

注意:如果#0存在,#1也是正确的语法:

$ 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 directorydrwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

如果你对更多感兴趣

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

man -Len -Pless\ +/^REDIRECTION bash

控制台中;-)

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.

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

这就像将错误传递给标准输出或终端一样。

也就是说,cmd不是命令:

$cmd 2>filenamecat filename
command not found

错误像这样发送到文件:

2>&1

标准错误被发送到终端。

重定向输入

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

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

[n]<word

重定向输出

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

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

[n]>word

移动文件描述符

重定向操作符,

[n]<&digit-

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

同样,重定向操作符

[n]>&digit-

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

参考:

man bash

键入/^REDIRECT以定位到redirection部分,并了解更多…

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

PS:

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

从程序员的角度来看,它的意思是:

dup2(1, 2);

手册页

理解2>&1复制也解释了为什么…

command >file 2>&1

…并不等同于…

command 2>&1 >file

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

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

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

如果您的系统上不存在/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

是速记

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

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

$命令&>文件

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

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

在此处输入图片描述

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

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

$命令>文件2>&1

这是将两个流重定向到文件的更常见的方法。首先标准输出被重定向到文件,然后标准错误被复制为与标准输出相同。所以两个流最终都指向file

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

在此处输入图片描述

现在Bash处理第一个重定向>文件。我们以前见过这个,它使标准输出指向文件:

在此处输入图片描述

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

在此处输入图片描述

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

不过要小心!写作

命令>文件2>&1

这与写作不同:

$命令2>&1>文件

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

在此处输入图片描述

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

在此处输入图片描述

现在Bash看到第二个重定向,>file,它将标准输出重定向到file:

在此处输入图片描述

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

在Bash中,写

$命令&>文件

与以下完全相同:

$命令>&文件

2>&1是一个POSIX shell构造。这是一个逐个标记的细分:


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

>&复制一个输出文件描述符运算符(输出重定向运算符>的变体)。给定[x]>&[y],由x表示的文件描述符被制作为输出文件描述符y的副本。

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

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


进一步解释:

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

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

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

unix_commands 2>&1

这用于将错误打印到终端。

  • 当产生错误时,它们被写入内存地址&2的“标准错误”缓冲区,2引用和来自该缓冲区的流。
  • 当产生产出时,它们被写入内存地址&1的“标准输出”缓冲区,1引用和来自该缓冲区的流。

所以回到命令。每当程序unix_commands产生错误时,它都会将其写入错误缓冲区。所以我们创建了一个指向缓冲区2的指针,并将错误>重定向到产出缓冲区&1。在这一点上,我们完成了,因为输出缓冲区中的任何内容都由终端读取和打印。

如果你是初学者,我发现这很有帮助这个

更新:
在Linux或Unix系统中,程序有两个地方将输出发送到:标准输出(stdout)和标准错误(stderr)。您可以将这些输出重定向到任何文件。

如果你这样做

ls -a > output.txt

控制台中不会打印任何内容,所有输出(标准输出)都被重定向到输出文件。

如果您尝试打印任何不退出的文件的内容,则意味着输出将是一个错误,例如打印当前目录中不存在的test.txt

cat test.txt > error.txt

输出将是

cat: test.txt :No such file or directory

但是error.txt文件将是空的,因为我们将标准输出重定向到一个不是stderr的文件。所以我们需要文件描述符(文件描述符只不过是一个表示打开文件的正整数。你可以说描述符是文件的唯一ID)来告诉shell我们要发送哪种类型的输出到文件。在Unix/Linux系统1用于stdout,2用于stderr中。

所以现在如果你这样做

ls -a 1> output.txt意味着你正在发送标准输出(stdout)到output.txt.

如果您这样做

cat test.txt 2> error.txt意味着您将标准错误(stderr)发送到error.txt。

&1用于引用文件描述符1(stdout)的值。

现在,2>&1表示“将stderr重定向到我们重定向stdout的同一位置”

现在你可以这样做

cat maybefile.txt > output.txt 2>&1

标准输出(stdout)和标准错误(stderr)都将重定向到output.txt.

感谢Ondrej K.的提醒

请注意,1>&2不能与2>&1互换使用。

假设你的命令依赖于管道,例如:
docker logs 1b3e97c49e39 2>&1 | grep "some log"
greping将在stderrstdout之间发生,因为stderr基本上合并到stdout中。

但是,如果您尝试:
docker logs 1b3e97c49e39 1>&2 | grep "some log"
greping不会真正搜索任何地方,因为Unix管道通过连接stdout | stdin连接进程,而第二种情况下的stdout被重定向到Unix管道不感兴趣的stderr

你需要从管道的角度来理解这一点。

$ (whoami;ZZZ) 2>&1  | catloganZZZ: command not found

正如你所看到的,管道的LHS的stdout和stderr都被送入RHS(管道)。

这与

$ (whoami;ZZZ) |& catloganZZZ: command not found