编辑
请不仅查看已接受的答案,还查看其他答案。
问题
为什么将 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