編輯
請不僅查看已接受的答案,還請查看其他答案。
問題
為什麼將 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。它們都引用相同的“開啟檔案”,並且共享當前位置和讀取/寫入模式。 (實際上使用 2>&1 和 2<&1 之間沒有任何區別。)
對於1>a.txt 2>a.txt
,兩個檔案描述符都是獨立開設並具有單獨的遊標位置。 (該檔案也會被截斷兩次。)如果您向fd #1 寫入“Hello”,其位置將提前到位元組5,但fd #2 仍保留在位元組0。覆蓋從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