在Unix shell中,如果我想要组合 stderr
和 stdout
进入 stdout
流进行进一步操作,我可以在命令的末尾添加以下内容:
2>&1
所以,如果我想使用 head
关于输出 g++
,我可以这样做:
g++ lots_of_errors 2>&1 | head
所以我只能看到前几个错误。
我总是很难记住这一点,而且我不得不去查找它,主要是因为我不完全理解这个特殊技巧的语法。
有人可以解决这个问题并逐字解释 2>&1
手段?
在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
和论点 排序。
符号 >
意思 重定向。
>
意思 发送到整个完整的文件,如果存在则覆盖目标(见 noclobber
bash功能 #3 后来)。>>
意思 发送除了 如果存在,将附加到目标。在任何情况下,如果文件不存在,将创建该文件。
为了测试这个,我们需要 一个简单的命令,它将在两个输出上发送一些东西:
$ 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! 随着新版本 庆典 (>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
为了这 特别 case,有一个快捷语法: &>
... 要么 >&
$ 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
$ 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
在一个 庆典 安慰 ;-)
数字指的是文件描述符(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工具,因此除非将其重定向到文件或其他内容,否则不会看到它。
该构造发送标准错误流(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
。
这允许一些非常复杂的技巧。
我在重定向上发现了这篇精彩的帖子: 所有关于重定向
将标准输出和标准错误重定向到文件
$ 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重定向到文件:
你看到这里发生了什么? Stdout现在指向文件,但是stderr仍然指向终端!写入stderr的所有内容仍会打印到屏幕上!所以要非常非常小心重定向的顺序!
还要注意在Bash中写作
$ command&> file
与以下内容完全相同:
$ command>&file
2>&1
是一个POSIX shell结构。以下是按令牌分类的令牌:
2
:“标准错误“输出文件描述符。
>&
: 复制输出文件描述符 运算符(。的变体) 输出重定向 操作者 >
)。特定 [x]>&[y]
,表示的文件描述符 x
使其成为输出文件描述符的副本 y
。
1
“标准输出“输出文件描述符。
表达方式 2>&1
复制文件描述符 1
到位置 2
,所以写入的任何输出 2
执行环境中的(“标准错误”)转到最初描述的同一文件 1
(“标准输出”)。
进一步说明:
文件描述符:“每个进程唯一的非负整数,用于标识用于文件访问的打开文件。”
标准输出/错误:请参阅以下注释 重定向 shell文档的一部分:
打开文件由以零开头的十进制数表示。最大可能的值是实现定义的;但是,所有实现都应支持至少0到9(包括0和9),以供应用程序使用。这些数字称为“文件描述符”。值0,1和2具有特殊含义和常规用途,并且由某些重定向操作暗示;它们分别称为标准输入,标准输出和标准误差。程序通常从标准输入中获取输入,并在标准输出上写入输出。错误消息通常写在标准错误上。重定向运算符可以在一个或多个数字之前(不允许插入字符)来指定文件描述符号。
回答你的问题:它需要任何错误输出(通常发送到stderr)并将其写入标准输出(stdout)。
当您需要对所有输出进行分页时,这有助于例如“更多”。有些程序喜欢将使用信息打印到stderr中。
帮助你记住
“2>&1”只是将发送到stderr的所有内容指向stdout。
我也建议阅读 关于错误重定向的这篇文章 详细介绍了这一主题。
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。
我建议你试着理解这些。
从程序员的角度来看,它恰恰意味着:
dup2(1, 2);
见 手册页。
理解这一点 2>&1
是一个 复制 也解释了原因......
command >file 2>&1
......和...不一样
command 2>&1 >file
第一个将两个流发送到 file
,而第二个将发送错误 stdout
,和普通输出 file
。
人们永远记得 paxdiablo关于这个问题的暗示 当前 重定向目标的位置......它 是 重要。
我个人的助记符 2>&1
运营商是这样的:
&
作为意义 'and'
要么 'add'
(角色是 ampers - 和,不是吗?)2
(stderr)去哪里 1
(stdout)已经/目前是和 加 两个溪流'。同样的助记符也适用于其他常用的重定向, 1>&2
:
&
含义 and
要么 add
...(你明白了&符号,是吗?)1
(stdout)去哪里 2
(stderr)已经/目前是和 加 两个溪流'。并且永远记住:你必须从右到左阅读“从末尾”重定向链(不 从左到右)。