入出力処理

なんらかの入力に対して加工を施し,結果を出力する。形こそ違え ソフトウェアは原則としてそのような動きを持つ。Ruby で作成するコンソールプログラムでの入出力の方法をまとめる。

コマンドライン引数

Rubyプログラム起動時に,そのプログラム名の後ろに指定された文字列は 単語ごとに区切られた配列として変数 ARGV に入る。

./program.rb a "b c" d\ ef ghi

としたときのARGVは

ARGV[0]ARGV[1] ARGV[2]ARGV[3]
"a""b c" "d ef""ghi"

となる。コマンドラインに指定した文字列の単語分解は シェルが規則に基づいて行なっている。

Rubyの場合はコマンドライン引数の個々をファイル名と見なし, そのファイルの中味全体を結合したファイル入力を自動的に利用することができる。 これは変数 ARGF を介して利用する。コマンドライン引数が何もない場合の ARGF は標準入力を指すオブジェクトとなる。

getsメソッドを単体で使用することは ARGF からの読み込みを意味する。つまり,

while line=gets
  ...
end

は,

while line=ARGF.gets
  ...
end

と同じである。

標準入出力

Rubyプログラムに引数を何も与えない場合,単体で呼ぶ gets メソッドは標準入力(STDIN; Standard Input)から読み込む。また, 単体で呼ぶ putsprintprintf メソッドは,標準出力(STDOUT; Standard Output)に書き出す。 標準入力・標準出力は,とくに指定がなければ端末に結び付けられる。 つまり,入力はキーボード,出力は仮想端末の画面となる。

これらは,シェルの持つリダイレクションやパイプの機能で 入出力先をファイルや別のプログラムに切り替えることができる。

> file 標準出力の行き先を file に切り替える
< file 標準入力の供給元を file に切り替える
program1| program2 program1の標準出力を program2 の標準入力につなぐ

いくつか例を示す。

# program.rbの出力結果を outfile に
./program.rb > outfile

# program.rbへの入力を infile から与える
./program.rb < infile

# ls -l の出力結果を program.rb に送る
ls -l | ./program.rb

# infileの内容を program.rb に渡し,その出力を wc -l に渡し,
# その出力を outfile に保存(下記いずれも同じ)
< infile ./program.rb | wc -l > outfile
./program.rb < infile | wc -l > outfile
./program.rb < infile | > outfile wc -l
< infile ./program.rb | > outfile wc -l

Rubyプログラムでは,起動時に引数を与えるとそれをファイルと見なして 単体の gets はそこからデータを読む。起動時に引数を与えた 場合でも必ず標準入力を読みたい場合は,明示的に標準入力を表す STDIN(あるいはそれが代入された変数 $stdin)から gets する。

while line = STDIN.gets
  〜処理〜
end

標準エラー出力

標準出力は処理した結果を出力するためのものである。処理に失敗したとき などのエラーメッセージは,標準エラー出力に出すべきである。簡単な例を示す。

print "整数を2で割った数を求めます。偶数を入れてください: "
n = gets.to_i
if n % 2 == 0 then		# 2で割った余りが0なら(偶数)
  printf("%d\n", n/2)		# 結果のみ出力
else
  printf("%dは偶数ではありません。\n", n) # エラーメッセージ出力
end

このプログラムをファイルへの出力リダイレクション付きで起動し, 奇数を入力すると以下のようになる。

./div2.rb > outfile
5
cat outfile
整数を2で割った数を求めます。偶数を入れてください: 5は偶数ではありません。

原則として,結果出力は次の処理の入力として利用するかもしれないので, 対話メッセージなどを含めても無意味だし,エラーメッセージが リダイレクトされてしまったら利用者には見えず警告の意味がなくなる。 利用者向けのメッセージなどは標準エラー出力に出す。Rubyでは STDERR(あるいは$stderr) にて出力する。 上記の例を書き直したものを示す。

STDERR.print "整数を2で割った数を求めます。偶数を入れてください: "
n = gets.to_i
if n % 2 == 0 then		# 2で割った余りが0なら(偶数)
  printf("%d\n", n/2)		# 結果のみ出力
else
  STDERR.printf("%dは偶数ではありません。\n", n) # エラーメッセージ出力
end

これを同じリダイレクションで実行する。

./div2.rb > outfile
整数を2で割った数を求めます。偶数を入れてください: 5
5は偶数ではありません。
cat outfile

# 何もない。結果がないことになるのでこれでよい。

本日の目次

yuuji@e.koeki-u.ac.jp