要将 stderr
和 stdout
组合到 stdout
流中,我们将其附加到命令中:
2>&1
例如,查看编译 g++ main.cpp
的前几个错误:
g++ main.cpp 2>&1 | head
2>&1
的具体含义是什么?
2>&1
比做 2>/dev/null 更好;-)
|&
是 2>&1 |
的简写。我不能说这是否适用于其他类似 bourne 的 shell,或者它是否是 zsh 唯一的功能。
文件描述符 1 是标准输出 (stdout
)。
文件描述符 2 是标准错误 (stderr
)。
起初,2>1
可能看起来像是将 stderr
重定向到 stdout
的好方法。但是,它实际上会被解释为“将 stderr
重定向到名为 1
的文件”。
&
表示后面和前面的是文件描述符,而不是文件名。因此,我们使用2>&1
。将 >&
视为重定向合并运算符。
要将标准输出重定向到 file.txt
:
echo test > file.txt
这相当于:
echo test 1> file.txt
要将 stderr 重定向到 file.txt
:
echo test 2> file.txt
所以 >&
是将一个 流 重定向 到另一个 文件描述符 的语法:
0 是标准输入
是标准输出
是标准错误
将标准输出重定向到标准错误:
echo test 1>&2 # equivalently, echo test >&2
要将标准错误重定向到标准输出:
echo test 2>&1
因此,在 2>&1
中:
2> 将 stderr 重定向到一个(未指定的)文件。
&1 将标准错误重定向到标准输出。
java ... 2&1 >> data.log
,我看到我的一位同事这样做了?
cmd 2>&1 >> somefile.log
会将 stdout/stderr 附加到文件中 - 它与上面基本相同,附加 >> file
cmd 2>&1 >>file
不会将 stderr 重定向到文件,但 cmd >> file 2>&1
会。订单很重要。在第一种情况下,stderr 被重定向到 shell 的 stdout(如果命令是交互式输入的,可能是 tty),然后 stdout 被定向到文件。第二种情况,stdout被定向到文件,然后stderr被定向到同一个地方。
0(or 1,2)>&0(or 1,2)
是否类似于控制输出的选项? echo test >test.log 2>&1
与 echo test 2>&1 >test.log
相同吗?
关于重定向的一些技巧
关于这一点的一些语法特殊性可能具有重要的行为。有一些关于重定向、STDERR
、STDOUT
和参数 ordering 的小示例。
1 - 覆盖或附加?
符号 >
表示 重定向。
> 表示发送到一个完整的文件,如果存在则覆盖目标(请参阅后面 #3 的 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
附录:注意!相同的新语法,两种方式:
$ 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 - 使用 |& 代替
语法 command |& ...
可用作 command 2>&1 | ...
的 别名。关于命令行顺序的相同规则适用。 What is the meaning of operator |& in bash? 上的更多详细信息
- 关于 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 控制台中;-)
我发现这篇关于重定向的精彩帖子:All about redirections
将标准输出和标准错误都重定向到文件
命令 &> 文件
这个单线使用 &>
运算符将两个输出流(stdout 和 stderr)从命令重定向到文件。这是 Bash 将两个流快速重定向到同一目的地的快捷方式。
以下是 Bash 重定向两个流后文件描述符表的样子:
https://i.stack.imgur.com/huKF2.png
如您所见,stdout 和 stderr 现在都指向 file
。因此,写入 stdout 和 stderr 的任何内容都会写入 file
。
有几种方法可以将两个流重定向到同一个目的地。您可以一个接一个地重定向每个流:
$ 命令>文件 2>&1
这是将两个流重定向到文件的更常见的方法。首先将 stdout 重定向到文件,然后将 stderr 复制为与 stdout 相同。所以两个流最终都指向 file
。
当 Bash 看到几个重定向时,它会从左到右处理它们。让我们通过这些步骤,看看这是如何发生的。在运行任何命令之前,Bash 的文件描述符表如下所示:
https://i.stack.imgur.com/1gsdY.png
现在 Bash 处理第一个重定向 >file。我们以前见过这个,它使标准输出指向文件:
https://i.stack.imgur.com/Ls39g.png
Next Bash 看到第二个重定向 2>&1。我们以前没有见过这种重定向。这将文件描述符 2 复制为文件描述符 1 的副本,我们得到:
https://i.stack.imgur.com/KnuSt.png
两个流都已重定向到文件。
不过这里要小心!写作
命令>文件2>&1
不等于写:
$ 命令 2>&1 > 文件
重定向的顺序在 Bash 中很重要!此命令仅将标准输出重定向到文件。 stderr 仍将打印到终端。要了解为什么会发生这种情况,让我们再次执行这些步骤。所以在运行命令之前,文件描述符表如下所示:
https://i.stack.imgur.com/OYgDd.png
现在 Bash 处理从左到右的重定向。它首先看到 2>&1,因此它将 stderr 复制到 stdout。文件描述符表变为:
https://i.stack.imgur.com/Jef1c.png
现在 Bash 看到第二个重定向 >file
,并将 stdout 重定向到文件:
https://i.stack.imgur.com/LR04L.png
你看到这里发生了什么吗?标准输出现在指向文件,但标准错误仍然指向终端!写入 stderr 的所有内容仍会打印到屏幕上!所以要非常非常小心重定向的顺序!
另请注意,在 Bash 中,写作
命令 &> 文件
与以下内容完全相同:
$ 命令>&文件
>&
的可选文件描述符
/dev/tty0
看到错误?
这些数字指的是文件描述符 (fd)。
零是标准输入
一个是标准输出
二是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
。
这允许一些非常复杂的诡计。
some_program 2>&1 > /dev/null
不能像这样工作:some_program > /dev/null 2>&1
。
如果您是初学者阅读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 文件将是空的,因为我们将标准输出重定向到一个文件而不是标准错误。
所以我们需要文件描述符(文件描述符只不过是一个正整数,代表一个打开的文件。你可以说描述符是文件的唯一 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.指出
2>1
2>&1
是一个 POSIX shell 构造。这是一个逐个标记的细分:
2
:“标准错误”输出文件描述符。
>&
:Duplicate an Output File Descriptor 运算符(Output Redirection 运算符 >
的变体)。给定 [x]>&[y]
,由 x
表示的文件描述符是输出文件描述符 y
的副本。
1
“标准输出”输出文件描述符。
表达式 2>&1
将文件描述符 1
复制到位置 2
,因此在执行环境中写入 2
(“标准错误”)的任何输出都会转到最初由 1
描述的同一文件(“标准输出”)。
进一步说明:
File Descriptor:“每个进程唯一的非负整数,用于标识打开的文件以进行文件访问。”
标准输出/错误:请参阅 shell 文档的 Redirection 部分中的以下注释:
打开的文件由从零开始的十进制数字表示。最大可能值是实现定义的;但是,所有实现都应支持至少 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。
我建议你试着理解这些。
perl test.pl > debug.log 2>&1
回答您的问题:它需要任何错误输出(通常发送到 stderr)并将其写入标准输出(stdout)。
例如,当您需要对所有输出进行分页时,这对“更多”很有帮助。一些程序喜欢将使用信息打印到标准错误中。
为了帮助你记住
= 标准输出(程序打印正常输出)
2 = 标准错误(程序打印错误)
"2>&1" 只是将发送到 stderr 的所有内容指向 stdout。
我还建议阅读this post on error redirecting,其中详细介绍了该主题。
从程序员的角度来看,这恰恰意味着:
dup2(1, 2);
请参阅 man page。
理解 2>&1
是一个副本也解释了为什么......
command >file 2>&1
……不等于……
command 2>&1 >file
第一个会将两个流都发送到 file
,而第二个会将错误发送到 stdout
,并将普通输出发送到 file
。
人们,永远记住paxdiablo关于重定向目标当前位置的提示......这很重要。
我对 2>&1
运算符的个人记忆是:
将 & 视为“和”或“加”的意思(字符是安培和,不是吗?)
所以它变成:'将 2 (stderr) 重定向到 1 (stdout) 已经/当前所在的位置并添加两个流'。
同样的助记符也适用于其他常用的重定向,1>&2
:
想想 & 的意思和或添加......(你明白 & 符号,是吗?)
所以它变成:'将 1 (stdout) 重定向到 2 (stderr) 已经/当前所在的位置并添加两个流'。
永远记住:你必须从右到左(而不是从左到右)“从头到尾”阅读重定向链。
重定向输入 输入重定向导致其名称由 word 扩展产生的文件打开以在文件描述符 n 上读取,如果未指定 n,则打开标准输入(文件描述符 0)。重定向输入的一般格式是: [n]
参考:
man bash
键入 /^REDIRECT
以定位到 redirection
部分,并了解更多...
在线版本在这里:3.6 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
是速记
unix_commands 2>&1
这用于将错误打印到终端。
当产生错误时,它们被写入内存地址 &2 处的“标准错误”缓冲区,以及来自该缓冲区的 2 个引用和流。
当产生输出时,它们被写入内存地址 &1 处的“标准输出”缓冲区,以及来自该缓冲区的 1 引用和流。
所以回到命令。每当程序 unix_commands
产生错误时,它都会将其写入 errors 缓冲区。因此,我们创建了一个指向该缓冲区 2
的指针,并将错误重定向 >
到 outputs 缓冲区 &1
。至此我们完成了,因为输出缓冲区中的任何内容都由终端读取和打印。
这就像将错误传递给标准输出或终端一样。
也就是说,cmd
不是命令:
$cmd 2>filename
cat filename
command not found
错误被发送到文件中,如下所示:
2>&1
标准错误被发送到终端。
0 表示输入,1 表示标准输出,2 表示标准错误。
提示:somecmd >1.txt 2>&1
正确,而 somecmd 2>&1 >1.txt
完全错误,没有任何效果!
您需要从管道的角度来理解这一点。
$ (whoami;ZZZ) 2>&1 | cat
logan
ZZZ: command not found
如您所见,管道 LHS 的 stdout 和 stderr 都被馈送到(管道的)RHS。
这与
$ (whoami;ZZZ) |& cat
logan
ZZZ: command not found
请注意,1>&2
不能与 2>&1
互换使用。
假设您的命令依赖于管道,例如:
docker logs 1b3e97c49e39 2>&1 | grep "some log"
grepping 将同时发生在 stderr
和 stdout
中,因为 stderr
基本上合并到 stdout
中。
但是,如果您尝试:
docker logs 1b3e97c49e39 1>&2 | grep "some log"
,
grepping 根本不会真正搜索任何地方,因为 Unix 管道正在通过连接 stdout | stdin
连接进程,并且在第二种情况下 stdout
被重定向到 stderr
Unix管道对此不感兴趣。
&2>&1
吗?&
在重定向上下文中仅被解释为表示“文件描述符”。写入command &2>&
被解析为command &
和2>&1
,即“在后台运行command
,然后运行命令2
并将其stdout重定向到它的stdout”。2>'&1'