在Unix shell中,如果我想将stderr
和stdout
合并到stdout
流中以进行进一步操作,我可以在命令的末尾附加以下内容:
2>&1
所以,如果我想在head
的输出上使用g++
,我可以这样做:
g++ lots_of_errors 2>&1 | head
所以我只能看到前几个错误。
我总是很难记住这一点,而且我经常要去查找它,这主要是因为我不完全理解这个特殊技巧的语法。
有人可以解决这个问题并按字符解释2>&1
的含义吗?
答案 0 :(得分:2208)
文件描述符1是标准输出(stdout
)
文件描述符2是标准错误(stderr
)。
以下是记住此构造的一种方法(虽然它并不完全准确):首先,2>1
可能看起来是将stderr
重定向到stdout
的好方法。但是,它实际上将被解释为“将stderr
重定向到名为1
的文件”。 &
表示后面是文件描述符而不是文件名。因此构造变为:2>&1
。
答案 1 :(得分:554)
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。
答案 2 :(得分:293)
关于此的一些语法特殊性可能具有重要的行为。有一些关于重定向的小样本,STDERR
,STDOUT
和参数排序。
符号>
表示重定向。
>
表示发送到整个已完成的文件,如果存在则覆盖目标(稍后请参阅#3 的noclobber
bash功能)。 >>
表示除之外的发送将附加到目标(如果存在)。在任何情况下,如果文件不存在,将创建该文件。
为了测试这个,我们需要一个简单的命令,它将在两个输出上发送一些东西:
$ 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 --->
请注意,此段落中的最后一个命令行与上一段完全相同,我写的似乎不是预期的行为(因此,这甚至可能是预期的行为)。< / p>
嗯,有一些关于重定向的技巧 对两个输出执行不同的操作:
$ ( 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
到另一个过滤器,最后两个输出合并通过第三个命令过滤器。
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
为了从给定命令重定向两个输出,我们看到正确的语法可能是:
$ ls -ld /tmp /tnt >/dev/null 2>&1
对于此特殊案例,有一种快捷语法:&>
...或>&
$ ls -ld /tmp /tnt &>/dev/null
$ ls -ld /tmp /tnt >&/dev/null
Nota:如果 2>&1
存在, 1>&2
也是正确的语法:
$ ls -ld /tmp /tnt 2>/dev/null 1>&2
$ 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/
您可以通过点击阅读精细手册:
man -Len -Pless\ +/^REDIRECTION bash
在bash控制台中; - )
答案 3 :(得分:82)
我在重定向上找到了这篇精彩的帖子: All about redirections
将标准输出和标准错误重定向到文件
$ command&amp;&gt; file
这个单行使用&>
运算符将两个输出流(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看到了第二个重定向>file
,它将stdout重定向到文件:
你看到这里发生了什么? Stdout现在指向文件,但是stderr仍然指向终端!写入stderr的所有内容仍会打印到屏幕上!因此,对重定向的顺序要非常非常小心!
另请注意,在Bash中,写作
$ command&amp;&gt; file
与:
完全相同$ command&gt;&amp; file
答案 4 :(得分:77)
数字指的是文件描述符(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工具,因此除非将其重定向到文件或其他内容,否则不会看到它。
答案 5 :(得分:54)
该构造将标准错误流(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
({{1} }}和然后将outfile1
重定向到stdout
。
这允许一些相当复杂的技巧。
答案 6 :(得分:17)
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。
我建议你试着理解这些。
答案 7 :(得分:17)
label
是一个POSIX shell结构。以下是按令牌分类的令牌:
for
:&#34; 标准错误&#34;输出文件描述符。
htmlFor
:Duplicate an Output File Descriptor运算符(Output Redirection运算符2>&1
的变体)。给定2
,>&
表示的文件描述符将成为输出文件描述符>
的副本。
[x]>&[y]
&#34; 标准输出&#34;输出文件描述符。
表达式x
将文件描述符y
复制到位置1
,因此执行时写入2>&1
(&#34;标准错误&#34;)的任何输出环境转到最初由1
描述的同一文件(&#34;标准输出&#34;)。
进一步解释:
File Descriptor:&#34;每个进程唯一的非负整数,用于标识打开文件以进行文件访问。&#34;
标准输出/错误:请参阅shell文档的Redirection部分中的以下注释:
打开的文件由以零开头的十进制数表示。最大可能的值是实现定义的;但是,所有实现都应支持至少0到9(包括0和9),以供应用程序使用。这些数字称为&#34;文件描述符&#34;。值0,1和2具有特殊含义和常规用途,并且由某些重定向操作暗示;它们分别称为标准输入,标准输出和标准误差。程序通常从标准输入中获取输入,并在标准输出上写入输出。错误消息通常写在标准错误上。重定向运算符前面可以有一个或多个数字(不允许插入字符)来指定文件描述符编号。
答案 8 :(得分:16)
回答你的问题:它需要输出任何错误(通常发送到stderr)并将其写入标准输出(stdout)。
当您需要对所有输出进行分页时,这有助于例如“更多”。有些程序喜欢将使用信息打印到stderr。
帮助你记住
“2&gt;&amp; 1”只是将发送到stderr的所有内容指向stdout。
我还建议阅读this post on error redirecting,其中详细介绍了这一主题。
答案 9 :(得分:16)
如果您是初学者,请阅读this
,这对我很有帮助。更新:
在Linux或Unix系统中,程序将输出发送到两个位置:标准输出(stdout)和标准错误(stderr)。您可以将这些输出重定向到任何文件。
就像您执行此操作一样
ls -a > output.txt
所有输出(stdout)都将重定向到输出文件,在控制台中什么也不会打印。
如果您尝试打印不退出的任何文件的内容,则输出将是错误的,就像您打印当前目录中不存在的test.txt一样
cat test.txt > error.txt
输出将为
cat: test.txt :No such file or directory
但是error.txt文件将为空,因为我们将标准输出重定向到了不是stderr的文件。
所以我们需要文件描述符(文件描述符只不过是代表打开的文件的正整数。您可以说描述符是文件的唯一ID)来告诉Shell我们将发送到文件的输出类型。在Unix / Linux系统中 1用于标准输出,2用于标准错误。
因此,现在如果执行此操作
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.指出
答案 10 :(得分:11)
从程序员的角度来看,这恰恰意味着:
input{
height: 0;
width: 0;
padding: 1000px 1000px;
background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Ara_ararauna_Luc_Viatour.jpg/1024px-Ara_ararauna_Luc_Viatour.jpg");
background-repeat: no-repeat;
}
请参阅man page。
了解dup2(1, 2);
是副本也解释了原因......
2>&1
......与......不一样。
command >file 2>&1
第一个会将两个流发送到command 2>&1 >file
,而第二个会将错误发送到file
,将普通输出发送到stdout
。
答案 11 :(得分:6)
人们总是记得 paxdiablo 关于重定向目标的当前位置的提示...... 重要。
2>&1
运营商的个人助记符是:
&
视为含义'and'
或'add'
(角色为&amp; - 和 强>,不是吗?)2
(stderr)重定向到1
(stdout)已经/当前的位置,添加两个流 同样的助记符也适用于其他常用的重定向,1>&2
:
&
含义and
或add
...(你明白了&符号,是吗?)1
(stdout)重定向到2
(stderr)已经/当前的位置,添加两个流 永远记住:你必须从右到左阅读“重定向链”(不从左到右)。
答案 12 :(得分:6)
如果您的系统中不存在/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
是简写
答案 13 :(得分:5)
这就像将错误传递给stdout或终端一样。
也就是说,cmd
不是命令:
$cmd 2>filename
cat filename
command not found
错误发送到文件,如下所示:
2>&1
标准错误发送到终端。
答案 14 :(得分:4)
重定向输入
重定向输入会导致名称为的文件 从扩展单词的结果打开文件阅读 描述符n,或标准输入(文件描述符0),如果n是 未指定。
重定向输入的一般格式为:
[n]<word
重定向输出
输出的重定向导致文件的输出 名称的结果来自要打开以供写作的单词的扩展 文件描述符n,或标准输出(文件描述符1),如果n 未指定。如果文件不存在则创建;如果它 确实存在它被截断为零大小。
重定向输出的一般格式为:
[n]>word
移动文件描述符
重定向运算符
[n]<&digit-
将文件描述符数字移动到文件描述符n,或者 标准输入(文件描述符0),如果未指定n。 数字在复制到n后关闭。
类似地,重定向运算符
[n]>&digit-
将文件描述符数字移动到文件描述符n,或者 标准输出(文件描述符1),如果未指定n。
man bash
键入/^REDIRECT
以找到redirection
部分,了解详情......
在线版本位于: 3.6 Redirections
很多时候,man
是学习Linux的强大工具。
答案 15 :(得分:3)
unix_commands 2>&1
这用于将错误打印到终端。
以下说明了过程
&2
所引用的标准错误存储器地址2
“缓冲区”中。&1
所引用的标准输出存储器地址1
“缓冲区”。因此,采用unix_commands
标准错误流2
,并将>
流(错误)重定向到标准输出内存地址&1
,以便它们流到终端并打印。
答案 16 :(得分:1)
0表示输入,1表示stdout,2表示stderr。
一个提示:
somecmd >1.txt 2>&1
是正确的,而somecmd 2>&1 >1.txt
完全错误没有效果!
答案 17 :(得分:0)
请注意,1>&2
不能与2>&1
互换使用。
假设您的命令取决于管道,例如:
docker logs 1b3e97c49e39 2>&1 | grep "some log"
由于stderr
已基本合并到stdout
中,因此stderr
和stdout
都会发生grepping。
但是,如果您尝试:
docker logs 1b3e97c49e39 1>&2 | grep "some log"
,
grepping根本不会真正在任何地方搜索,因为Unix管道通过连接stdout | stdin
连接进程,而第二种情况下的stdout
被重定向到Unix管道不感兴趣的stderr
。>