在Unix shell中,如果我想要组合stderr
并stdout
进入stdout
流进行进一步操作,我可以在命令的末尾添加以下内容:
2>&1
所以,如果我想head
在输出上使用g++
,我可以这样做:
g++ lots_of_errors 2>&1 | head
所以我只能看到前几个错误.
我总是很难记住这一点,而且我不得不去查阅它,主要是因为我不完全理解这个特殊技巧的语法.
有人可以打破这个并按字符解释具体2>&1
意义吗?
文件描述符1是标准输出(stdout
).
文件描述符2是标准错误(stderr
).
这里是要记住这个结构(尽管它并不完全准确)的一种方法:首先,2>1
可能看起来像重定向的好办法stderr
来stdout
.但是,它实际上将被解释为"重定向stderr
到名为1
" 的文件.&
表示后面是文件描述符而不是文件名.所以构造变成:2>&1
.
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.
关于此的一些语法特殊性可能具有重要的行为.有一个关于重定向,一些小的样本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 --->
请注意,此段落中的最后一个命令行与上一段中的完全相同,我写的内容似乎不是预期的行为(因此,这甚至可能是预期的行为).
好吧,有一些关于重定向的技巧, 在两个输出上做不同的操作:
$ ( 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控制台;-)
我在重定向上找到了这篇精彩的帖子:所有关于重定向的内容
将标准输出和标准错误重定向到文件
$ command&> file
这个单行使用&>
运算符将两个输出流(stdout和stderr)从命令重定向到文件.这是Bash快速将两个流重定向到同一目的地的快捷方式.
以下是Bash重定向两个流后文件描述符表的样子:
正如你所看到的,stdout和stderr现在都指向了file
.因此写入stdout和stderr的任何内容都会被写入file
.
有两种方法可以将两个流重定向到同一目标.您可以一个接一个地重定向每个流:
$ command> file 2>&1
这是将两个流重定向到文件的更常见方法.第一个stdout被重定向到文件,然后stderr被复制到与stdout相同.所以这两个流最终都指向了file
.
当Bash看到几个重定向时,它会从左到右处理它们.让我们完成这些步骤,看看会发生什么.在运行任何命令之前,Bash的文件描述符表如下所示:
现在Bash处理第一个重定向>文件.我们之前看过这个,它使stdout指向文件:
下一个Bash看到第二个重定向2>&1.我们之前没有见过这种重定向.这个复制文件描述符2是文件描述符1的副本,我们得到:
两个流都已重定向到文件.
不过要小心!写作
命令>文件2>&1
与写作不同:
$ command 2>&1>文件
重定向的顺序在Bash中很重要!此命令仅将标准输出重定向到文件.stderr仍会打印到终端.要理解为什么会发生这种情况,让我们再次讨论这些步骤.所以在运行命令之前,文件描述符表如下所示:
现在Bash处理从左到右的重定向.它首先看到2>&1所以它将stderr复制到stdout.文件描述符表变为:
现在Bash看到第二个重定向,>file
并将stdout重定向到file:
你看到这里发生了什么?Stdout现在指向文件,但是stderr仍然指向终端!写入stderr的所有内容仍会打印到屏幕上!所以要非常非常小心重定向的顺序!
还要注意在Bash中写作
$ command&> file
与以下内容完全相同:
$ command>&file
数字指的是文件描述符(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工具,因此除非将其重定向到文件或其他内容,否则不会看到它.
该构造将标准错误stream(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>&1
是一个POSIX shell构造.这是按令牌分类的令牌:
2
:" 标准错误 "输出文件描述符.
>&
:复制输出文件描述符运算符(输出重定向运算符的变体>
).给定[x]>&[y]
,表示的文件描述符x
是输出文件描述符的副本y
.
1
" 标准输出 "输出文件描述符.
表达式将2>&1
文件描述符复制1
到位置2
,因此2
在执行环境中写入("标准错误")的任何输出都转到最初由1
("标准输出")描述的同一文件.
进一步说明:
文件描述符:"每个进程唯一的非负整数,用于标识用于文件访问的打开文件."
标准输出/错误:请参阅shell文档的Redirection部分中的以下注释:
打开的文件由以零开头的十进制数表示.最大可能的值是实现定义的; 但是,所有实现都应支持至少0到9(包括0和9),以供应用程序使用.这些数字称为"文件描述符".值0,1和2具有特殊含义和常规用途,并且由某些重定向操作暗示; 它们分别称为标准输入,标准输出和标准误差.程序通常从标准输入中获取输入,并在标准输出上写入输出.错误消息通常写在标准错误上.重定向运算符可以在一个或多个数字前面(不允许插入字符)来指定文件描述符号.
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.
我建议你试着去理解这些.
回答你的问题:它需要任何错误输出(通常发送到stderr)并将其写入标准输出(stdout).
当您需要对所有输出进行分页时,这有助于例如"更多".有些程序喜欢将使用信息打印到stderr中.
为了帮助你记住
1 =标准输出(程序打印正常输出)
2 =标准错误(程序打印错误)
"2>&1"只是将发送到stderr的所有内容指向stdout.
我还建议阅读这篇关于错误重定向的帖子,其中详细介绍了该主题.
从程序员的角度来看,它恰恰意味着:
dup2(1, 2);
请参见手册页.
理解这2>&1
是一个副本也解释了为什么......
command >file 2>&1
......和...不一样
command 2>&1 >file
第一个将发送两个流file
,而第二个将发送错误stdout
,并将普通输出发送到file
.
人们,永远记得paxdiablo关于重定向目标当前位置的暗示......这很重要.
我对2>&1
运营商的个人助记符是这样的:
想到&
意义'and'
或'add'
(角色是一个安瓿 - 而且,不是吗?)
所以它变成:'重定向2
(stderr)到where 1
(stdout)已经/当前是并添加两个流'.
同样的助记符也适用于其他常用的重定向,1>&2
:
想想&
意思and
或add
......(你明白了&符号,是吗?)
所以它变成: '重定向1
(stdout)到where 2
(stderr)已经/当前是并添加两个流'.
永远记住:你必须从右边到左边(不是从左到右)读取重定向链.
如果/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或终端一样.
也就是说,cmd
不是命令:
$cmd 2>filename cat filename command not found
错误发送到文件,如下所示:
2>&1
标准错误发送到终端.
重定向输入
输入的重定向导致打开其名称由单词扩展产生的文件,以供在文件描述符n上读取;如果未指定n,则打开标准输入(文件描述符0)。
重定向输入的一般格式为:
[n]重定向输出
输出重定向导致打开其名称由单词扩展产生的文件,以便在文件描述符n上进行写操作;如果未指定n,则打开标准输出(文件描述符1)。如果文件不存在,则创建该文件;如果确实存在,则将其截断为零大小。
重定向输出的一般格式为:
[n]>word移动文件描述符
重定向运算符,
[n]<&digit-将文件描述符数字移动到文件描述符n,或者如果未指定n,则将标准输入(文件描述符0)移动到文件描述符n。数字复制到n后关闭。
同样,重定向运算符
[n]>&digit-将文件描述符数字移动到文件描述符n,或者如果未指定n,则将标准输出(文件描述符1)移动到文件描述符n。
man bash
键入/^REDIRECT
以找到该redirection
部分,并了解更多信息...
在线版本在这里:3.6重定向
很多时候,它man
是学习Linux的强大工具。