有关Bash中的重定向
&>
在Bash中是什么意思?
关于错误的git status 2&>1 > /dev/null
...
有人能澄清一下man手册,并解释这个语法究竟在发生什么吗?
可以的。我也在尝试理解各种行为和bash语法,让我们一起通过这个语句和一些例子来更好地了解。
快速摘要
- 如果你只想理解问题中奇怪/错误语法的完整含义:
git status 2&>1 > /dev/null
,请直接跳到下面的第1节。
- 如果你只是基于问题标题来到这里:“在bash中&>是什么意思?”,请直接跳到下面的第2节。
- 如果你想要一个快速参考bash中正确重定向用法的摘要,例如通过
2>&1
将stderr重定向到stdout,或通过>file
或1>file
将stdout重定向到文件,或通过2>file
将stderr重定向到文件,或通过&>file
或>file 2>&1
将同时将stdout和stderr重定向到文件,请查看下面的第3节:“3. bash中正确重定向的摘要”。
- 如果你只想测试你对重定向的奇怪、冗余、覆盖或其他非标准用法的理解,请查看下面的第4节。
1. git status 2&>1 > /dev/null
语句的解析
这个语句中:
git status 2&>1 > /dev/null
有三个独立的部分,分别如下(尽管这并不直观或明显,特别是考虑到在2&>1
中2
和&>1
之间没有空格):
git status 2
&>1
> /dev/null
如果你拥有以下内容,它们与上述内容都非常不同。我们将在本答案后面讨论这些内容。
2&>1
2>&1
2>1
Statement 1 (git status 2
) runs git status 2
. Here, 2
is a parameter passed to git status
. Since it's not a valid option, git status
assumes it to be a path, which can be a file or directory. So, git returns the status of all files named 2
, or of all files within a directory named 2
. As man git status
shows, a better way to specify paths is to separate options from paths with --
, like this:
git status -- 2
Obviously, that's not what you're trying to do. :)
Statement 2 (&>1
) redirects stdout and stderr to a file named 1
. This is also obviously not what you are trying to do. :) The &>file
syntax redirects all stdout and stderr to file
. You can read about this in the bash manual online here, or by running man bash
and and searching for the section named "Redirecting Standard Output and Standard Error". We'll go over this section of the manual more later.
Note that &>1
(written as 2&>1
--two separate statements: 2
and &>1
, in your question) is not the same syntax nor concept as 2>&1
. The latter, 2>&1
, redirects file descriptor 2
(stderr) to file descriptor 1
(stdout), where the 3 primary file descriptors are:
0
= stdin
1
= stdout
2
= stderr
Statement 3 (> /dev/null
): this is where it starts to get tricky. This can also be written without the space, as >/dev/null
. It redirects stdout (file descriptor 1
) to the /dev/null
Linux pseudofile, which discards any output written to it. Writing >/dev/null
is exactly identical to 1>/dev/null
, as file descriptor 1
(stdout) is implied as the default option if not specified, as the bash manual states. Read more about it in the "Redirecting Output" section of the bash manual here.
It starts to get tricky here for two reasons:
- First, because the
1
means two different things: in &>1
the one is a file named "1". This is likely a mistake on the user's part, but that's what it is. In >/dev/null
there is an implied 1 as in 1>/dev/null
, and that refers to file descriptor 1, which is stdout
.
- Second, it is tricky because you have redirection overrides going on, where the last one sticks.
&>1
redirects both stdout and stderr to a file named "1", but 1>/dev/null
then redirects stdout to the "/dev/null" file. The latter redirection of stdout overrides the former, so the end result is that stderr
is redirected to a file named "1" and stdout
is redirected to the "/dev/null" file. This could have also been written as:
2>1 1>/dev/null
&>1 > /dev/null
上述信息需要更多解释,因此让我们更详细地解释
&>
,然后总结如何在bash中正确进行重定向。
2. 仅针对这个问题的标题:“在bash中
&>
是什么?” 正如@Casey Jones在他的(不幸的是)已删除的答案
中所暗示的,我认为bash手册最好地解释了它:
https://www.gnu.org/software/bash/manual/bash.html#Redirecting-Standard-Output-and-Standard-Error
从中我们得知,所有这4种语法几乎相同,第一种建议优于第二种,第三种是在bash之外更通用的方法:
&>file
>&file
>file 2>&1
1>file 2>&1
因此,&>file
的意思是“将 标准输出 和 标准错误输出 都重定向到 file
文件中。”
这是手册如何表述的:
3.6.4 Redirecting Standard Output and Standard Error
This construct allows both the standard output (file descriptor 1) and the standard error output (file descriptor 2) to be redirected to the file whose name is the expansion of word.
There are two formats for redirecting standard output and standard error:
&>word
and
>&word
Of the two forms, the first is preferred. This is semantically equivalent to
>word 2>&1
When using the second form, word may not expand to a number or ‘-’. If it does, other redirection operators apply (see Duplicating File Descriptors below) for compatibility reasons.
3. bash中正确重定向的总结
文件描述符提醒:
0
= stdin
1
= stdout
2
= stderr
你应该使用的良好、正确的语法:
2>&1
1>&2
>file
1>file
2>file
&>file
>&file
>file 2>&1
1>file 2>&1
例子:
printf "%s " "hey" 2
printf "%s " "hey" 2 >file
printf "%s " "hey" 2 1>file
printf "%s " "hey" 2 2>file
printf "%s " "hey" 2 &>file
printf "%s " "hey" 2&>file
printf "%s " "hey" 2 >file 2>&1
printf "%s " "hey" 2 1>file 2>&1
4. "奇怪"的例子,我们将它们呈现为 "谜题",以便教授和测试理解
printf "%s " "hey" 2 >1 >2 >3 >4 >5
printf "%s " "hey" 2 1>1 1>2 1>3 1>4 1>5
grep '' *
printf "%s " "hey" 21>1 1>2 1>3 1>4 1>5
printf "%s " "hey" 2>1 1>2 1>3 1>4 1>5
printf --invalid_arg "%s " "hey" 2>1 1>2 1>3 1>4 1>5
printf "%s " "hey" 2 &>1 1>2 1>3 1>4 1>5
printf "%s " "hey" 2&>1 1>2 1>3 1>4 1>5
printf "%s " "hey" 2&>1 >2 >3 >4 >5
printf "%s " "hey" 2 &>1 >2 >3 >4 >5
printf "%s " "hey" 2 >1 2>&1 >2 >3 >4 >5
printf "%s " "hey" 2 1>1 2>&1 >2 >3 >4 >5
printf "%s " "hey" 2>1 1>2 1>3 1>4 1>5
git status 2>&1
不同于git status 2&>1
) - M.M