当“2>&1”发布在 1>x 之前时,它会做什么?

han*_*rik 17 bash command-line pipe cmd.exe

我知道这个命令的作用:

\n
command 1>/dev/null 2>&1\n
Run Code Online (Sandbox Code Playgroud)\n

但是,如果有的话,下面的代码有什么作用呢?

\n
command 2>&1 1>/dev/null\n
Run Code Online (Sandbox Code Playgroud)\n

我仍然看到第二个命令的标准错误输出,所以它至少没有达到我预期的效果......

\n

这在 Windows/cmd.exe 和 Linux/Bash 上都被重现(我本来想在Unix & Linux而不是 Super\xc2\xa0User 上问这个问题,但我注意到它也可以在 Windows cmd.exe 上重现,所以我猜它在 Super\xc2\xa0User 上比在 Unix 和 Linux 上更适合?)

\n

gle*_*man 26

另一个示例可能会有所帮助:让我们将 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
Run Code Online (Sandbox Code Playgroud)

我们可以看到将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 )
Run Code Online (Sandbox Code Playgroud)


Cyr*_*rus 12

man bash

“请注意,重定向的顺序很重要。例如,命令

ls > dirlist 2>&1
Run Code Online (Sandbox Code Playgroud)

将标准输出和标准错误定向到文件目录列表,而命令

ls 2>&1 > dirlist
Run Code Online (Sandbox Code Playgroud)

仅将标准输出定向到文件 dirlist,因为在标准输出重定向到 dirlist 之前,标准错误已从标准输出复制。”


Mok*_*bai 7

这是操作顺序的问题。您希望2>&1重定向到1,但它却重定向到的当前1。这感觉有点像“竞争条件”,但实际上并非如此,您期望两个操作同时发生,但它们是一个接一个地进行评估的,并且该特定时刻的值才是重要的,而不是最终值。

默认情况下,1指向您的默认控制台输出stdout,因此2>&1此时将重定向stderr到您的标准控制台输出stdout

通过在 重定向到另一个文件2>&1 1执行此操作,您可以将其重定向到指向的文件指针。1( /dev/null)

本质上,重定向运算符复制重定向到的指针,而不是指向其他描述符。因此,重定向的顺序很重要。

  • [竞争条件](/sf/ask/2415731/) 当两个(或更多)_simultaneous_ 线程或进程(或其他)尝试同时执行操作时发生,没有同步,因此结果取决于外部因素,基本上是随机的。这绝对不是这样的:重定向的处理定义得很好,并且完全按照从左到右的顺序发生。 (2认同)
  • @SeñorCMasMas:我会这样称呼它:将命令式语法(告诉 shell 执行操作的*指令*)误解为声明性语法(shell 应在其下运行命令的*配置*)。重定向是前者,但很容易被误读为后者。 (2认同)

ike*_*ami 5

1>/dev/null 2>&1:
1 (stdout): /dev/null
2 (stderr): /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
Run Code Online (Sandbox Code Playgroud)
            Original           After 1>/dev/null  After 2>&1
            -----------------  -----------------  -----------------
1 (stdout): /tmp/stdout        /dev/null          /dev/null
2 (stderr): /tmp/stderr        /tmp/stderr        /dev/null
Run Code Online (Sandbox Code Playgroud)

现在,让我们看看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
Run Code Online (Sandbox Code Playgroud)
            Original           After 2>&1         After 1>/dev/null
            -----------------  -----------------  -----------------
1 (stdout): /tmp/stdout        /tmp/stdout        /dev/null
2 (stderr): /tmp/stderr        /tmp/stdout        /tmp/stdout
Run Code Online (Sandbox Code Playgroud)

演示

a:

#!/usr/bin/perl
print STDOUT "Sent to STDOUT\n";
print STDERR "Sent to STDERR\n";
Run Code Online (Sandbox Code Playgroud)
$ ( exec 1>/tmp/stdout 2>/tmp/stderr; ./a )

$ cat /tmp/stdout; echo .
Sent to STDOUT
.

$ cat /tmp/stderr; echo .
Sent to STDERR
.
Run Code Online (Sandbox Code Playgroud)
$ ( exec 1>/tmp/stdout 2>/tmp/stderr; ./a 2>&1 1>/dev/null )

$ cat /tmp/stdout; echo .
Sent to STDERR
.

$ cat /tmp/stderr; echo .
.
Run Code Online (Sandbox Code Playgroud)
$ ( exec 1>/tmp/stdout 2>/tmp/stderr; ./a 1>/dev/null 2>&1 )

$ cat /tmp/stdout; echo .
.

$ cat /tmp/stderr; echo .
.
Run Code Online (Sandbox Code Playgroud)