为什么2&& 1必须在|之前出现(管道),但在“"之后myfile" (重定向到文件)? [英] Why does 2>&1 need to come before a | (pipe) but after a "> myfile" (redirect to file)?
问题描述
将stderr与stdout结合使用时,为什么2>&1
需要在|
(管道)之前但在> myfile
(重定向到文件)之后?
要将stderr重定向到stdout以输出文件:
echo > myfile 2>&1
要将stderr重定向到管道的stdout:
echo 2>&1 | less
我的假设是我可以做:
echo | less 2>&1
,它可以工作,但不能.为什么不呢?
管道是命令的|分隔列表.您指定的任何重定向都适用于组成命令(简单或复合),但不适用于整个管道.每个管道通过隐式将重定向应用于每个子外壳之前,将与一个命令关联的任何重定向求值,从而将一个命令的stdout链接到下一命令的stdin.
cmd 2>&1 | less
第一个子shell的第一个stdout重定向到正在读取less
的管道.接下来,将2>&1
重定向应用于第一个命令.将stderr重定向到stdout起作用,因为stdout已经指向管道.
cmd | less 2>&1
此处,重定向适用于less
. Less的stdout和stderr可能都是以指向终端的方式开始的,因此2>&1
在这种情况下无效.
如果您希望重定向应用于整个管道,将多个命令作为管道的一部分进行分组或嵌套管道,请使用命令组(或任何其他 compound命令):
{ { cmd1 >&3; cmd2; } 2>&1 | cmd3; } 3>&2
可能是一个典型的例子.最终结果是:cmd1
和cmd2
的stderr-> cmd3
; cmd2
的标准输出-> cmd3
;和cmd1
和cmd3
的stderr,以及cmd3
的stdout->终端.
如果使用特定于Bash的|&
管道,事情会变得很奇怪,因为每个管道的stdout重定向仍然首先发生,但stderr重定向实际上是最后发生.例如:
f() { echo out; echo err >&2; }; f >/dev/null |& cat
现在,与直觉相反,所有输出都被隐藏. f
的第一个stdout进入管道,f
的下一个stdout重定向到/dev/null
,最后,stderr重定向到stdout(仍然是/dev/null
).
我建议不要在Bash中使用|&
-在这里用于演示.
When combining stderr with stdout, why does 2>&1
need to come before a |
(pipe) but after a > myfile
(redirect to file)?
To redirect stderr to stdout for file output:
echo > myfile 2>&1
To redirect stderr to stdout for a pipe:
echo 2>&1 | less
My assumption was that I could just do:
echo | less 2>&1
and it would work, but it doesn't. Why not?
A pipeline is a |-delimited list of commands. Any redirections you specify apply to the constituent commands (simple or compound), but not to the pipeline as a whole. Each pipe chains one command's stdout to the stdin of the next by implicitly applying a redirect to each subshell before any redirects associated with a command are evaluated.
cmd 2>&1 | less
First stdout of the first subshell is redirected to the pipe from which less
is reading. Next, the 2>&1
redirect is applied to the first command. Redirecting stderr to stdout works because stdout is already pointing at the pipe.
cmd | less 2>&1
Here, the redirect applies to less
. Less's stdout and stderr both presumably started out pointed at the terminal, so 2>&1
in this case has no effect.
If you want a redirect to apply to an entire pipeline, to group multiple commands as part of a pipeline, or to nest pipelines, then use a command group (or any other compound command):
{ { cmd1 >&3; cmd2; } 2>&1 | cmd3; } 3>&2
Might be a typical example. The end result is: cmd1
and cmd2
's stderr -> cmd3
; cmd2
's stdout -> cmd3
; and cmd1
and cmd3
's stderr, and cmd3
's stdout -> the terminal.
If you use the Bash-specific |&
pipe, things get stranger, because each of the pipeline's stdout redirects still occur first, but the stderr redirect actually comes last. So for example:
f() { echo out; echo err >&2; }; f >/dev/null |& cat
Now, counterintuitively, all output is hidden. First stdout of f
goes to the pipe, next stdout of f
is redirected to /dev/null
, and finally, stderr is redirected to stdout (/dev/null
still).
I recommend never using |&
in Bash -- it's used here for demonstration.
这篇关于为什么2&& 1必须在|之前出现(管道),但在“"之后myfile" (重定向到文件)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!