Basic stderr stdout redirection in bash



我想知道如何正确理解以下内容:

在我的脑海中,我首先将STDOUT重定向到文件,然后,我将STDERR重定向到STDOUT。然而,这似乎适得其反:

$ perl -e "print STDERR 'stderr'; print STDOUT 'stdout'" >file 2>&1
$ cat file
stderrstdout

现在,我假设我首先将STDERR重定向到STDOUT,因此STDOUTSTDERR都连接到STDOUT然后STDOUT重定向到文件。

$ perl -e "print STDERR 'stderr'; print STDOUT 'stdout'" 2>&1 >file
stderr
$ cat file
stdout

看来我误解了我应该如何阅读这篇文章。有人可以向我解释一下吗?

2>&1并没有将stderr指向stdout。它不会以任何方式将两个流合并为一个。没有混叠或还原。

相反,2>&1将stderr指向stdout当前指向的位置,而不是stdout本身。之后,您可以自由更改标准输出指向的位置,而不会影响标准输出。

你可以这样想> file 2>&1

stdout=terminal stderr=terminal  # inherited default
stdout=file                      # > file
stderr=$stdout                   # 2>&1
echo "stdout=$stdout"            # result: stdout=file
echo "stderr=$stderr"            # result: stderr=file

所以两个输出都到了文件,就像你所看到的一样。

同样,2>&1 > file将是:

stdout=terminal stderr=terminal  # inherited default
stderr=$stdout                   # 2>&1
stdout=file                      # > file
echo "stdout=$stdout"            # result: stdout=file
echo "stderr=$stderr"            # result: stderr=terminal

所以stderr去了终端,就像你看到的那样。

实际实现基本上就是这样,但使用 dup2() 而不是分配给 fd,open()而不是分配给 file

在你的第一个示例中,bash 在调用 perl 之前设置了重定向。 重定向按您的描述排列:标准输出转到文件,标准错误转到同一文件。 然后perl运行,并首先输出到错误,然后输出到输出。 由于错误和输出指向同一文件,因此文件将按打印顺序填充

在第二个示例中,2>&1将标准错误重定向到默认标准输出的位置(控制台)。 然后关闭标准输出默认值并重定向到文件(通过 >file )。 这里重要的一点是,当您关闭重定向时,所有别名重定向也会关闭并恢复到其之前的位置。 在这种情况下,标准错误将恢复到控制台,而标准输出将返回到新文件。

我用语言来描述可见的效果,而不是谈论bash如何在引擎盖下实现这一点。

最新更新