【クイズ】現実逃避のためのSTDOUT, STDERR 〜その2〜

ここ が前回。

クイズ〜その1〜

[bash]
$ perl -e ‘print "1\n" ; warn "2\n";'
[/bash]

これですが、普通に
[bash]
$ 1
$ 2
[/bash]

と表示されるだけです。まあ別に問題ない。

クイズ〜その2〜

[bash]
$ perl -e ‘print "1\n" ; warn "2\n";’ >a.txt
[/bash]

これですが、
[bash]
$ 2
[/bash]
となります。

1 がどこに消えたかというと、
[bash]
$ cat a.txt
[/bash]
で出てきます。

この結果の違いは、標準出力と標準エラー出力の違いのためです。
標準出力は、画面への出力、または、次のコマンドに対して標準入力
のどちらかとなります。
それに対して、標準エラー出力は、ユーザの目に見える形に直接出力します。

図で見る

[bash]
$ perl -e ‘print "1\n" ; warn "2\n";'
[/bash]
の場合を見てみると…

となるので、両方ともディスプレイに表示されます。

次は、grepを使ってみます。
[bash]
$ perl -e ‘print "1\n" ; warn "2\n";’ | grep 1
[/bash]
とした場合です。

この場合の挙動は
[bash]
$ 2
$ 1
[/bash]
となり、さっきとは逆の出力となります。
これを表した図が下のものです。

2 が先に出力されているのは、図の状況のためです。
標準エラー出力は、パイプによって grep に渡されないので、直接ディスプレイに出力された。
一方、標準出力はパイプによって、 grep に標準入力とされた。その後ディスプレイに出力された。

そんなわけで、
a.txt に 1 が記述されていて、
プロンプトには 2 が出力された、と。

標準出力と標準エラー出力っていうのは別々で出力しているんだよ、っていうお話です。

2>&1

ちなみに、標準出力も標準エラー出力も同じファイルに出力したい…という時は
[bash]
$ perl -e ‘print "1\n" ; warn "2\n";’ >a.txt 2>&1
[/bash]
とします。

1 が標準出力
2 が標準エラー出力を挿しています。
>a.txt も
1>a.txt も同じ意味です。

2>&1 は「2の出力先を1の出力先と同じにする」という意味を持っています。

注意

注意する点としては、
1>a.txt 2>&1

2>&1 1>a.txt
は違います。

前者は
1 の出力先を a.txt と設定し、
2 の出力先を 1 と同じにする。
つまり、
1 の出力先 a.txt
2 の出力先 a.txt
です。

後者は
2 の出力先を 1 と同じとして、
1 の出力先を a.txt と設定する。
つまり、
1 の出力先 a.txt
2 の出力先 default (ディスプレイ)
となります。

きっかけ

そもそもなぜこんなことをしているかというと、
いい加減、>/dev/null 2>&1と書くのをやめたらどうか (追記あり)
ここを見たからです。

[bash]
$ perl -e ‘print "1\n" ; warn "2\n";’ 1>a.txt 2>a.txt
[/bash]

について少し悩みましたが、「よく考えればそりゃそうだ」っていう結論。頭が固い…。

ていうか

ぐぐれば速攻出てきたので、考えたのは一体なんだったのか状態…。
まあ、パズルみたいで楽しかったです。
卒論の現実逃避にもなりましたし。

最後に

[bash]
$ perl -we ‘syswrite(STDERR,"1\n");syswrite(STDOUT,"2\n");syswrite(STDOUT,"3\n");syswrite(STDERR,"4\n")’ > a.txt 2> a.txt
[/bash]
が分かりませんでした。
そもそも、卒論中でちゃんと考えきれていないので、これから考えていきます。

3>&-
とか
4>&1
とかも今後…。

ぐぐりたくないでござる。
しばらく考えて分からなければ、周りに聞いて、それでダメなら、ぐぐってみます。