「標準出力」「標準エラー出力」とは?
ここでは "Hello, world!" を、少し掘り下げてみましょう。
Console.WriteLine("Hello, world!");
このコードは、一言で言えば「文字を出力する」ということですが、ちゃんと言えば「標準出力に文字を出力する」ことです。
そもそも「『標準出力』に出力する」ということは、一体どういうことでしょうか。
「標準出力」の仲間にはこの他、「標準エラー出力」とか「標準入力」というのもあります。 今回は「標準出力」と「標準エラー出力」について説明します。
プロセス起動時にファイルハンドルを渡す
Windows で「プログラムを実行する」ということは、CreateProcess 系の API でプロセスとそのプロセスのメインスレッドを作成して、それを実行することと言えます。
コンソールプログラムであれば、コマンドプロンプト (cmd.exe) がプロセスを起動しますし、 エクスプローラで EXE ファイルをダブルクリックして実行するような場合は、エクスプローラがプロセスを起動することになります。
あるプロセスが他のプロセスを起動するときには、起動時のパラメータとして、 「出力はこのファイルに書き込んでください」「エラーの出力はこのファイルに書き込んでください」 「入力はこのファイルから受け取れますよ」と指定するために、いくつかファイルハンドルを渡します。
まさに、これらがそれぞれ、「標準出力」「標準エラー出力」「標準入力」になります。
cmd.exe が実行可能プログラムを起動する場合には、これらのファイルハンドルが (あの黒い) コンソール画面への入出力に繋がっています。
このため起動された側のプログラムで「標準出力」や「標準エラー」に出力すると、コンソール画面 (コマンドプロンプト) に文字が出力されるのです。
コンソールでのリダイレクト
「標準出力」と「標準エラー出力」をコンソールでリダイレクトする
次の C# のコードでは、Console で WriteLine メソッドを使って、画面に文字を出力しています。
using System; namespace Test1 { class Program { static void Main(string[] args) { Console.WriteLine("Hello, StdOut!"); Console.Error.WriteLine("Hello, StdErr!"); } } }
このうち、最初の行 Console.WriteLine() は標準出力への出力で、 二番目の行 Console.Error.WriteLine() は標準エラー出力への出力になっています。
このプログラムをビルドして実行してみます。
C:\test> Test1 Hello, StdOut! Hello, StdErr!
標準出力も標準エラー出力も同様に表示されました。
これだけ見た限りでは同じに見えるのですが、実は内部的には違いがあります。出力先のファイル (ハンドル) が違います。
試しに > で、標準出力をテキストファイルにリダイレクトしましょう。
C:\test> Test1 > out.std Hello, StdErr!
すると、画面には標準エラーの内容だけが表示されました。リダイレクトによって標準出力の内容は out.std という、 今新しくできたテキストファイルの中に出力されたのです。
C:\test> dir /b out.std Test1.exe
確かにファイルができています。
dir コマンドの /b オプションはファイル名だけを表示します。
type コマンドでファイルの中身を表示してみます。
C:\test> type out.std Hello, StdOut!
確かに標準出力に出力した内容ですね。
標準エラー出力の内容をリダイレクトするには、次のように 2> とします。
C:\test> Test1 2> out.err Hello, StdOut! >type out.err Hello, StdErr!
これを実行すると画面には標準出力の内容が表示され、標準エラー出力への内容は out.err というファイルにリダイレクトされました。
リダクレクト記号 > につけた 2 という番号は、標準エラー出力を表すファイルディスクリプタです。もともと UNIX 系の OS でファイルテーブルエントリの識別子になるものですが、 Windows のコマンドプロンプトでも同様に使えます。
ちなみに標準出力のファイルディスクリプタは 1 です。> と書くことは、 1> と同じ意味になります。
標準出力を「捨てる」
ついでに言うと、nul にリダイレクトすると、出力内容を捨てることができます。画面にもファイルにも出力されません。
C:\test> Test1 2> nul Hello, StdOut!
エラー出力だけを取り出したいとか、あるいはその逆に、エラー出力以外を取得したいと言う場合に、こうしたリダイレクトを知っておくと便利です。
開発時の注意点
このように、同じくコンソールに文字を出力するとしても、標準出力に出力することと、標準エラー出力に出力することには違いがあります。
コンソールプログラムを開発する場合には、面倒くさがらずに、通常の予定された動作は標準出力へ出力し、エラー系のメッセージは標準エラー出力に出力するようにしておきましょう。
これによって、エラーメッセージだけを抜き取るなどの作業がプログラムで自動化できたりします。