編集
承認された回答だけでなく、他の回答もご覧ください。
質問
1>[FILENAME] 2>&1 と同じように見えるのに、STDOUT と STDERR の両方を同じファイルにリダイレクトすると機能しないのはなぜですか?
次に例を示します。
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
両方のリダイレクトはファイルを切り捨てるので、2番目(実行順)は最初のリダイレクトを上書きします。
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
、両方のファイル記述子は独立開業カーソル位置が別々になります。(ファイルも 2 回切り捨てられます。) fd #1 に「Hello」を書き込むと、その位置はバイト 5 に進みますが、fd #2 はバイト 0 のままです。fd #2 に印刷すると、0 から始まるデータが上書きされるだけです。
2 番目の書き込みが短いかどうかは簡単にわかります。
$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>a.txt
$ cat a.txt
123defg
Perl には内部バッファリングがあるため、この例では、fd #1 のデータが fd #2 のデータの前に書き込まれるようにするために、明示的な flush() が必要です。そうしないと、終了時にストリームが予期しない順序でフラッシュされてしまいます。
比較すると、ファイル記述子が共有されている場合、書き込みは次々に実行されます。
$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>&1
$ cat a.txt
abcdefg
123