我知道这个命令的作用:
command 1>/dev/null 2>&1
但是,如果有的话,下面的操作会做什么呢?
command 2>&1 1>/dev/null
我仍然看到第二个命令的标准错误输出,所以它至少没有按照我的预期去做......
这在 Windows/cmd.exe 和 Linux/Bash 上都有重现(我正要问这个问题Unix 和 Linux而不是超级用户,但我注意到它也可以在 Windows cmd.exe 上重现,所以我想它更适合超级用户而不是 Unix 和 Linux?)
答案1
进一步的例子可能会有所帮助:让我们将 fd1 重定向到一个文件,将 fd2 重定向到 fd1,然后将 fd1 重定向到另一个文件:
$ ( echo "this is stdout"; echo "this is stderr" >&2 ) 1>foo 2>&1 1>bar
$ cat foo
this is stderr
$ cat bar
this is stdout
我们可以看到将2>&1
stderr 发送到 stdout 重定向到的“foo”文件,但是当我们将 stdout 重定向到“bar”时,我们不会改变 stderr 的目的地。
类似地,2>&1 1>/dev/null
将 stderr 重定向到 stdout 指向的任何位置(参见/proc/$$/fd
),并且当 stdout 被丢弃时, stderr 不会被改变(仍然可见)。
这是用于捕获命令的错误输出的技术,忽略常规输出:
error_output=$( some_command 2>&1 1>/dev/null )
答案2
从man bash
:
“请注意,重定向的顺序很重要。例如,命令
ls > dirlist 2>&1
将标准输出和标准错误都定向到文件 dirlist,而命令
ls 2>&1 > dirlist
仅将标准输出定向到文件 dirlist,因为在标准输出重定向到 dirlist 之前,标准错误已从标准输出复制。”
答案3
这是操作顺序的问题。你希望2>&1
重定向到1
,但它却重定向到了当前价值而1
不是。这有点像“竞争条件”,但实际上并非如此,你希望两个操作同时发生,但它们会一个接一个地进行评估,并且特定时刻的值才是最重要的,而不是最终值。
默认情况下1
指向您的默认控制台输出stdout
,因此2>&1
此时执行的操作是重定向stderr
到您的标准控制台输出stdout
。
通过做 2>&1
后重定向1
到另一个文件您正在将其重定向到新的指向文件的指针1
。(/dev/null
)
本质上是重定向运算符副本指向您要重定向到的源位置的指针,而不是指向其他描述符。因此,重定向的顺序很重要。
答案4
1>/dev/null 2>&1
:
1(标准输出):/dev/null
2(标准错误):/dev/null
2>&1 1>/dev/null
:
1 (stdout):/dev/null
2 (stderr):1 (stdout) 的原始目标
顺序很重要,因为它们是从左到右处理的,使用当时描述符的当前值。
让我们看一下1>/dev/null 2>&1
两种不同的起始条件:
Original After 1>/dev/null After 2>&1
----------------- ----------------- -----------------
1 (stdout): /dev/tty /dev/null /dev/null
2 (stderr): /dev/tty /dev/tty /dev/null
Original After 1>/dev/null After 2>&1
----------------- ----------------- -----------------
1 (stdout): /tmp/stdout /dev/null /dev/null
2 (stderr): /tmp/stderr /tmp/stderr /dev/null
现在,让我们看看2>&1 1>/dev/null
相同的起始条件。
Original After 2>&1 After 1>/dev/null
----------------- ----------------- -----------------
1 (stdout): /dev/tty /dev/tty /dev/null
2 (stderr): /dev/tty /dev/tty /dev/tty
Original After 2>&1 After 1>/dev/null
----------------- ----------------- -----------------
1 (stdout): /tmp/stdout /tmp/stdout /dev/null
2 (stderr): /tmp/stderr /tmp/stdout /tmp/stdout
演示
a
:
#!/usr/bin/perl
print STDOUT "Sent to STDOUT\n";
print STDERR "Sent to STDERR\n";
$ ( exec 1>/tmp/stdout 2>/tmp/stderr; ./a )
$ cat /tmp/stdout; echo .
Sent to STDOUT
.
$ cat /tmp/stderr; echo .
Sent to STDERR
.
$ ( exec 1>/tmp/stdout 2>/tmp/stderr; ./a 2>&1 1>/dev/null )
$ cat /tmp/stdout; echo .
Sent to STDERR
.
$ cat /tmp/stderr; echo .
.
$ ( exec 1>/tmp/stdout 2>/tmp/stderr; ./a 1>/dev/null 2>&1 )
$ cat /tmp/stdout; echo .
.
$ cat /tmp/stderr; echo .
.