编辑

编辑

编辑

请不仅查看已接受的答案,还查看其他答案。

问题

为什么将 STDOUT 和 STDERR 重定向到同一个文件不起作用,尽管它看起来与 1>[FILENAME] 2>&1 相同?

以下是一个例子:

perl -e 'print "1\n" ; warn "2\n";' 1>a.txt 2>a.txt
cat a.txt
# outputs '1' only.

好吧,为什么?我认为这是可行的,因为...STDOUT 被重定向到 a.txt,STDERR 也是如此。STDERR 怎么了?

答案1

两个重定向都会截断文件,因此第二个重定向(按执行时间顺序)将覆盖第一个重定向。尝试

rm a.txt ; touch a.txt ; perl -e 'print "1\n" ; warn "2\n";' 1>>a.txt 2>>a.txt

或者只使用相同的文件描述符

perl -e 'print "1\n" ; warn "2\n";' 1>a.txt 2>&1

答案2

其中1>a.txt 2>&1,文件描述符 #1 是重复到 #2。它们都引用同一个“打开的文件”,并且都共享当前位置和 r/w 模式。(使用 2>&1 和 2<&1 实际上没有任何区别。)

使用时1>a.txt 2>a.txt,两个文件描述符都是独立开设并具有单独的光标位置。(文件也会被截断两次。)如果您将“Hello”写入 fd #1,其位置将前进到字节 5,但 fd #2 仍位于字节 0。打印到 fd #2 只会覆盖从 0 开始的数据。

如果第二次写入更短,则很容易看出这一点:

$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>a.txt

$ cat a.txt 
123defg

请注意,Perl 具有内部缓冲,因此在此示例中,需要显式 flush() 以确保 fd #1 数据在 fd #2 数据之前写入。否则,退出时流将以不可预测的顺序刷新。

为了进行比较,如果文件描述符是共享的,则写入只会相互跟随:

$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>&1

$ cat a.txt 
abcdefg
123

相关内容