要将stderr和stdout合并到stdout流中,我们将其附加到命令中:
2>&1
例如,查看编译g++main.cpp时的前几个错误:
g++ main.cpp 2>&1 | head
2>&1的详细含义是什么?
要将stderr和stdout合并到stdout流中,我们将其附加到命令中:
2>&1
例如,查看编译g++main.cpp时的前几个错误:
g++ main.cpp 2>&1 | head
2>&1的详细含义是什么?
当前回答
2> &1是POSIX外壳构造。以下是逐个令牌的细分:
2:“标准错误”输出文件描述符。
>&:复制输出文件描述符运算符(输出重定向运算符>的变体)。给定[x]>&[y],由x表示的文件描述符被制作为输出文件描述符y的副本。
1“标准输出”输出文件描述符。
表达式2>&1将文件描述符1复制到位置2,因此在执行环境中写入2的任何输出(“标准错误”)都将转到最初由1描述的相同文件(“标准输出”)。
进一步解释:
文件描述符:“每个进程唯一的非负整数,用于标识用于文件访问的打开文件。”
标准输出/错误:请参阅shell文档的重定向部分中的以下注释:
打开的文件由以零开头的十进制数字表示。最大的可能值是定义的实现;然而,所有实现都应支持至少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。
我建议你试着理解这些。
注意,1>&2不能与2>&1互换使用。
假设您的命令依赖于管道,例如:docker日志1b3e97c49e39 2>&1|grep“一些日志”grepping将在stderr和stdout之间发生,因为stderr基本上被合并到stdout中。
但是,如果您尝试:docker日志1b3e97c49e39 1>&2|grep“一些日志”,grepping根本不会在任何地方搜索,因为Unix管道通过连接stdout|stdin来连接进程,而在第二种情况下,stdout被重定向到stderr,Unix管道对此没有兴趣。
关于重定向的一些技巧
这方面的某些语法特殊性可能具有重要的行为。这里有一些关于重定向、STDERR、STDOUT和参数排序的小示例。
1-覆盖还是附加?
符号>表示重定向。
>意味着作为一个完整的文件发送到,如果存在则覆盖目标(请参阅后面的noclobber bash特性)。>>表示除了发送之外,如果存在,将附加到目标。
在任何情况下,如果文件不存在,将创建该文件。
2-shell命令行依赖于顺序!!
为了测试这一点,我们需要一个简单的命令,它将在两个输出上发送一些信息:
$ 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。
附录: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到另一个,最后合并的两个输出通过第三个命令过滤器。
2b-改用|&
语法命令|&。。。可以用作命令2>&1|…的别名。。。。关于命令行顺序的规则也适用。更多详细信息,请参见bash中运算符|&的含义是什么?
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
在bash控制台中;-)
该构造将标准错误流(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重定向到outile2。
这允许一些相当复杂的诡计。
文件描述符1是标准输出(stdout)。文件描述符2是标准错误(stderr)。
首先,2>1可能是将stderr重定向到stdout的好方法。然而,它实际上会被解释为“将stderr重定向到名为1的文件”。
&指示后面和前面的是文件描述符,而不是文件名。因此,我们使用2>&1。考虑>&成为重定向合并运营商。