我想知道如何正确理解以下内容:
在我的脑海中,我首先将STDOUT
重定向到文件,然后,我将STDERR
重定向到STDOUT
。然而,这似乎适得其反:
$ perl -e "print STDERR 'stderr'; print STDOUT 'stdout'" >file 2>&1
$ cat file
stderrstdout
现在,我假设我首先将STDERR
重定向到STDOUT
,因此STDOUT
和STDERR
都连接到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如何在引擎盖下实现这一点。