当“2>&1”在 1>x 之前发布时它起什么作用?

当“2>&1”在 1>x 之前发布时它起什么作用?

我知道这个命令的作用:

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>&1stderr 发送到 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 .
.

相关内容