在shell中,“2>&1”是什么意思?
在Unix shell中,如果我想将stderr
和stdout
结合到stdout
stream中进行进一步的操作,我可以在我的命令结尾附加以下内容:
2>&1
所以,如果我想在g ++的输出上使用“head”,我可以这样做:
g++ lots_of_errors 2>&1 | head
所以我只能看到前几个错误。
我总是记不起这件事,而且我经常不得不去查看它,主要是因为我不完全理解这个特殊技巧的语法。 有人可以把这个分开来解释一个字符是什么“2>&1”的意思吗?
文件描述符1是标准输出(stdout)。
文件描述符2是标准错误(stderr)。
这里有一个方法来记住这个构造(尽pipe它不是完全准确的):首先, 2>1
可能看起来像是将stderrredirect到stdout的一个好方法。 但是,它实际上会被解释为“将stderrredirect到名为1
的文件”。 &
表示接下来是文件描述符而不是文件名。 所以构造变成: 2>&1
。
echo test > afile.txt
redirect到afile.txt
。 这和做..一样
echo test 1> afile.txt
redirect标准错误,你做..
echo test 2> afile.txt
>&
是将streamredirect到另一个文件描述符的语法 – 0是stdin。 1是stdout。 2是stderr。
您可以通过执行将stdoutredirect到stderr。
echo test 1>&2 # or echo test >&2
..或相反亦然:
echo test 2>&1
所以,总之.. 2>
redirectstderr到一个(未指定的)文件,附加&1
redirect标准输出到标准输出
关于redirect的一些技巧
对此的一些语法特殊性可能具有重要的行为。 有一些关于redirect, STDERR
, STDOUT
和参数sorting的小样本。
1 – 覆盖或附加?
符号>
意味着redirect 。
-
>
表示发送完整的文件 ,覆盖目标(如果存在的话)(见#3后面的noclobber
bashfunction)。 -
>>
意指如果存在则除了追加目标外。
任何情况下,文件将被创build,如果他们不存在。
2 – shell命令行依赖于顺序!
为了testing这个,我们需要一个简单的命令来发送两个输出 :
$ 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 --->
请注意,本段中的最后一个命令行与之前的paraghaph中的命令行完全相同,在那里我写的似乎不是预期的行为 (所以这甚至可能是预期的行为)。
那么有一些关于redirect的技巧, 在两个输出上做不同的操作 :
$ ( 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
。
附录:nota! 随着新版本的bash ( >4.0
),有一个新的function和更性感的语法来做这种事情:
$ 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
通过一个特定的filter, STDERR
到另一个,最后两个输出合并通过第三个命令filter。
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 – 最后一招和更多…
为了redirect来自给定命令的输出,我们看到正确的语法可以是:
$ 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 -es/^/++/ ++/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 -es/^/++/ /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控制台;-)
数字是指文件描述符(fd)。
- 零是
stdin
- 一个是
stdout
- 两个是
stderr
2>&1
将fd 2redirect到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工具,使用非标准的文件描述符进行自定义日志logging,所以除非将其redirect到文件或其他东西,否则不会看到它。
该构造将标准错误stream( stderr
)发送到标准输出( stdout
)的当前位置 – 此货币问题似乎被其他答案忽略了。
您可以使用此方法将任何输出句柄redirect到另一个输出句柄,但最常用于将stdout
和stderr
stream引导到单个stream中进行处理。
一些例子是:
# 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
– 它会将它redirect到参数遇到时的stdout
( outfile1
), 然后将stdout
redirect到outfile2
。
这允许一些相当复杂的欺骗。
我发现这个redirect的精彩文章: 所有关于redirect
将标准输出和标准错误redirect到一个文件
$命令&>文件
这一行代码使用&>操作符将两个输出stream(stdout和stderr)从命令redirect到文件。 这是bash快速将两个streamredirect到相同的目的地。
以下是在bashredirect两个stream后文件描述符表的外观:
正如你可以看到stdout和stderr现在指向文件。 所以写入stdout和stderr的任何东西都被写入文件。
有两种方法可以将两个streamredirect到同一个目的地。 您可以逐个redirect每个stream:
$ command> file 2>&1
这是将两个streamredirect到文件的更常见的方式。 第一个stdout被redirect到文件,然后stderr被复制为与stdout相同。 所以两个stream最终都指向文件。
当bash看到几个redirect时,它会从左向右处理它们。 我们来看看这些步骤是怎么发生的。 在运行任何命令之前,bash的文件描述符表如下所示:
现在bash处理第一个redirect>文件。 我们已经看到了这一点,它使stdout指向文件:
下一个bash会看到第二个redirect2>&1。 我们之前没有看到这个redirect。 这个复制文件描述符2是文件描述符1的副本,我们得到:
两个stream都被redirect到文件。
不过要小心! 写作:
命令>文件2>&1
写作不一样:
$命令2>&1>文件
redirect的顺序在bash中很重要! 该命令仅将标准输出redirect到文件。 stderr仍然会打印到terminal。 为了理解为什么会发生这种情况,我们再来一遍。 所以在运行命令之前,文件描述符表如下所示:
现在bash处理redirect从左到右。 它首先看到2>&1,所以它复制stderr到标准输出。 文件描述符表变成:
现在bash看到第二个redirect>文件,它将stdoutredirect到文件:
你看到这里发生了什么? Stdout现在指向文件,但stderr仍然指向terminal! 所有写到stderr的东西仍然会被打印到屏幕上! 所以要非常小心,redirect的顺序!
另外请注意,在bash中,写这个:
$命令&>文件
完全一样:
$命令>&文件
要回答你的问题:它会带来任何错误输出(通常发送到stderr)并将其写入标准输出(stdout)。
这对于所有输出需要分页时的“更多”有帮助。 有些程序将打印使用信息打印到stderr中。
帮助你记住
- 1 =标准输出(程序打印正常输出)
- 2 =标准错误(程序打印错误)
“2>&1”只是将发送到stderr的所有内容都指向标准输出。
我也build议阅读这篇文章的错误redirect在这个主题是全面详细介绍。
2是控制台标准错误。
1是控制台标准输出。
这是Unix的标准,Windows也遵循POSIX。 例如,当你跑步
perl test.pl 2>&1
标准错误被redirect到标准输出,所以你可以看到两个输出在一起。
perl test.pl > debug.log 2>&1
执行后,您可以在debug.log中看到所有的输出,包括错误。
perl test.pl 1>out.log 2>err.log
然后标准输出到out.log,标准错误到err.log。
我build议你试着去理解这些。
2>&1
是一个POSIX shell结构。 这是一个细分,令牌令牌:
2
:“ 标准错误 ”输出文件描述符。
>&
: 复制输出文件描述符运算符( 输出redirect运算符>
一个变体)。 给定[x]>&[y]
,将由x
表示的文件描述符设为输出文件描述符y
的副本。
1
“ 标准输出 ”输出文件描述符。
expression式2>&1
文件描述符2>&1
复制到位置2
,因此执行环境中写入2
(“标准错误”)的任何输出将转到原来由1
(“标准输出”)描述的相同文件。
进一步解释:
文件描述符 :“每进程唯一的非负整数,用于标识为文件访问而打开的文件”。
标准输出/错误 :请参阅shell文档redirect部分中的以下注释:
打开的文件由从零开始的十进制数表示。 最大的可能值是实现定义的; 然而,所有的实现应该支持至less0到9,包括在内,供应用程序使用。 这些数字被称为“文件描述符”。 值0,1和2具有特殊含义和常规用途,并由某些redirect操作所暗示; 它们分别被称为标准input,标准输出和标准错误。 程序通常从标准input中获取input,并在标准输出上写入输出。 错误消息通常写在标准错误上。 redirect操作符之前可以有一个或多个数字(不允许插入字符)指定文件描述符编号。
从程序员的angular度来看,这意味着:
dup2(1, 2);
看手册页 。
理解2>&1
是副本也解释了为什么…
command >file 2>&1
…不一样…
command 2>&1 >file
第一个将两个stream发送到file
,而第二个将发送错误stdout
,普通输出到file
。
人们总是记得paxdiablo关于redirect目标的当前位置的暗示…这很重要。
我个人对2>&1
运算符的记忆是这样的:
- 想象
&
意思'and'
或'add'
(字符是一个悲剧 – 是不是?) - 因此,它变成: 'redirect
2
(标准错误)到1
(标准输出)已经/当前所在的位置,并添加两个stream' 。
同样的助记符也适用于其他常用的redirect, 1>&2
:
- 想想
&
意义and
或者add
…(你有关于&符号的想法,是吗?) - 所以它变成: 'redirect
1
(标准输出)到2
(stderr)已经/当前所在的位置,并添加两个stream' 。
永远记住:你必须从头到尾阅读redirect链,从右到左( 而不是从左到右)。
这就像把错误标记到标准输出或terminal。 即, cmd不是命令$ cmd 2> filename cat filename命令未find
发送到文件的错误就像发送到terminal的2>&1错误
redirectinput
input的redirect会导致文件描述符n中打开由单词扩展引起的名称的文件,或者读入文件描述符n的标准input(文件描述符0)(如果未指定n)。
redirectinput的一般格式是:
[n]<word
redirect输出
输出的redirect会导致文件描述符n中打开名称由扩展名引起的文件,如果未指定n,则输出标准输出(文件描述符1)。 如果该文件不存在,则创build它; 如果它确实存在,它将被截断为零大小。
redirect输出的一般格式是:
[n]>word
移动文件描述符
移动文件描述符redirect操作符
[n]<&digit-
将文件描述符数字移动到文件描述符n或标准input(文件描述符0),如果未指定n。 数字复制到n后closures。
同样,redirect操作符
[n]>&digit-
将文件描述符数字移动到文件描述符n或标准输出(文件描述符1)(如果未指定n)。
参考:
man bash
键入/^REDIRECT
定位到redirection
部分,了解更多..
在线版本在这里:
http://www.gnu.org/software/bash/manual/bashref.html#Redirections
PS:
很多时候, man
是学习linux的强大工具
假设你的系统中不存在/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
是速记
0表示input,1表示标准输出,2表示标准错误。
一个提示 : somecmd >1.txt 2>&1
是正确的,而somecmd 2>&1 >1.txt
是完全错误的没有效果!