こんにちは!Webコーダー・プログラマーの貝原(@touhicomu)です。
今日は、Rubyの標準入力について、書きたいと思います。いきなり「標準入力」と言っても、何が「標準」で何が「入力」なのか、わかりづらいですよね。そのため、
- Rubyにおける標準入力の意味
- 標準入力を利用して、キーボードからの入力をRubyで受け取る方法
- 複数行のキーボードからの入力を標準入力としてRubyの配列で受け取る方法
という基本的な内容から、
- 標準入力オブジェクトを持っている変数$stdin、定数STDINを使って標準入力からキーボードの入力を受け取る方法
- コマンドラインの引数をRubyで受け取る方法
- whileとgets、lineを使って、何度も標準入力からキーボードの入力を受け取る方法
といった応用的な内容についても解説していきます。
標準入力とは
標準入力とは、UNIXにおけるキーボード入力のことです。試しにターミナルで cat コマンドを以下のように使ってみてください。
cat コマンドを「cat –」で起動すると、標準入力であるキーボードの入力を、そのまま画面に表示します。(cat コマンドは、入力された文字列をそのまま画面に出力するコマンドです)
$ cat -
すると、「cat -」と入力した直下で、入力カーソルが点滅します。ここにキーボードから文字を入力できます。試しに「hello, world」と入力してみましょう。入力の最後では改行キーを押下します。
$ cat - hello, world hello, world
1番目の「hello, world」は、キーボードから入力した文字です。2番目の「hello, world」が、cat コマンドが、キーボード入力から得た文字をそのまま画面に表示したものです。
このように、標準入力とは、キーボードから入力した文字をコマンドへ渡すやり方なのです。これだけでは、わかりにくいと思いますので、次章以降で、実際にRubyでコードを書いていきましょう。
標準入力の基本的な使い方
Rubyで標準入力を利用する
Rubyでは、キーボードから入力した標準入力を扱うことのできるメソッドが複数あります。キーボードは一つなのに、メソッドが複数あることで混乱してしまいそうですね。
でも、整理して覚えれば意外にすんなり覚えられます。キーボードで入力した文字列の入り口が一つで、その入り口に入ってきた文字列を取り扱うことのできる方法(メソッド)が複数あるということです。
そのメソッドの一つがgetsです。getsは、「get string」の略で、意味はそのまま、「標準入力にキーボード入力された文字列を取得する」という意味です。
このgetsを使って、サンプルプログラムを組んで、Rubyで標準入力を扱ってみましょう。なお、getsは、キーボードの入力を1行ずつ取得します。
p '文字を入力してください。' input = gets p input
[実行結果]
$ ruby gets.rb "文字を入力してください。" こんにちは。 "こんにちは。n"
gets で得たキーボードで入力した文字列「こんにちは。」を変数inputに入れ、pでinputを出力しています。「n」は改行文字です。pによる出力の中に改行文字が入っていますね。改行文字を取り除きたい!というときは、chomp!というメソッドで簡単に解決できます。
chomp!は、文字列に使用すると、
- 文字列の末尾に改行文字があった場合、改行文字を削除する
- 文字列の末尾に改行文字がなかった場合、なにもしない
という動作をします。このように、chomp!はgetsなどのメソッドの仕様を解決するために生み出されたメソッドです。
p '文字を入力してください。' input = gets p input.chomp!
[実行結果]
$ ruby gets_chomp.rb "文字を入力してください。" こんにちは。 "こんにちは。"
chomp!付きのサンプルコードの実行結果では、変数inputの末尾の改行文字「n」が削除されていますね。
複数行入力
getsメソッドは、キーボードからの入力文字を、1行しか取得できませんでした。しかし、readlinesメソッドを使用すれば、複数行のキーボードからの入力文字を取得できます。
redalinesは、複数行の文字列を、1行ごとの配列として取得します。配列の要素は、1行分の文字列です。注意点として、getsと違い、改行を入力しても、キーボードからの入力は終了しないということです。
代わりに、キーボードからの入力を終了するには、「Ctrl+D(あるいはCTRL+Z)」を入力します。
[サンプルコード]
p '文字を入力してください' input = readlines p input
[実行結果]
$ ruby readines.rb "文字を入力してください" a1 a2 a3 ["a1n", "a2n", "a3n"]
「a3」の末尾のところで、Ctrl+Dを入力しています。複数行入力した結果は、文字列の配列になっています。
標準入力を表す変数$stdin、定数STDIN
Rubyでは、標準入力をオブジェクトとしてあらかじめ持っています。Rubyで標準入力オブジェクトにアクセスするには、$stdin変数か、STDIN定数にアクセスします。
「stdin」とは、「Standard Input」の略語で、「標準入力」という意味です。以下、具体例を入れて解説していきます。
$stdinとgets
今まで、getsにはレシーバとなるオブジェクトを指定していませんでした。レシーバを指定しないgetsは標準入力をデフォルトの入力先として動作します。
今度は、より具体的にgetsにレシーバの$stdinを指定してみましょう。以下の、サンプルコードを見てきます。
p "何か入力してください。" input = $stdin.gets p input
[実行結果]
$ ruby ruby_stdin_gets.rb "何か入力してください。" こんにちは。 "こんにちは。n"
以上のように、getsのレシーバに$stdinを指定して使用したときでも、レシーバなしのgetsを使ったときと同じく、標準入力からの入力を文字列として取り出しています。これは、定数STDINを使ったときでも同様です。
p "何か入力してください。" input = STDIN.gets p input
[実行結果]
$ ruby ruby_stdin_gets2.rb "何か入力してください。" こんばんは。 "こんばんは。n"
以上のように、getsのレシーバに定数STDINを指定して使用したときでも、getsのレシーバに変数$stdinを指定して使用したときと同じ動作をします。
$stdinとreadlines、read
getsは$stdinやSTDINをレシーバにしても、レシーバがないときと同じ動作をしました。readlinesメソッドに、$stdin、STDINをレシーバに指定した場合も、レシーバのないreadlinesと同じ動作をします。
実際にサンプルコードで確かめてみましょう。
p '文字を入力してください' input = $stdin.readlines p input
[実行結果]
"文字を入力してください" a1 a2 a3 ["a1n", "a2n", "a3n"]
以上のように、readlinesのレシーバに$stdinを指定したときでも、readliinesにレシーバをしていない場合と同じく、標準入力からの複数行の入力を配列に変換しています。
次に、readメソッドのレシーバに$stdinを指定した際の動作を、実際のサンプルコードで確認してみましょう。readメソッドは、ファイルの内容を一気に読み込んで文字列として返すメソッドです。
今回の場合は、標準入力の入力からCTRL+D(あるいはCTRL+Z)までを一気に読み込んで文字列として返します。
p '文字を入力してください' input = $stdin.read p input
[実行結果]
"文字を入力してください" line1 line2 line3 "line1nline2nline3n"
以上のように、readのレシーバに$stdinを指定すると、標準入力からCTRL+D(あるいはCTRL+Z)が入力されるまでの間の複数行の入力をすべて一気に読み込んでいます。そして、読み込んだ内容を文字列として返しています。
標準入力の応用的な使い方
もう一つの標準入力、ARGV
Rubyスクリプトの実行時にも、標準入力から、Rubyスクリプトに値を与えることができます。ターミナルでRubyスクリプトを実行する際に、
$ ruby argv.rb a
などのように指定すれば、Rubyスクリプトに、値「a」が渡ります。このターミナル上で与えられた値は、Rubyスクリプトでは、「ARGV」という変数に配列として保持されています。
実際にRubyスクリプトを組んで、標準入力から値「a」が渡っていることを確認してみましょう。
[サンプルコード]
p ARGV[0]
[実行結果]
$ ruby argv.rb a "a"
上記のように、値「a」は、RubyスクリプトのARGV配列の0番目に、文字列「”a”」として入っています。次に、応用として、ターミナルの標準入力から複数の値を渡してみましょう。
ターミナル上で、値を空白で区切って複数個指定すると、それらの値はRubyスクリプトでは、ARGV変数に配列で格納されます。ARGV変数からは、配列の要素として、ターミナル上で指定された値を取得できます。
ここでは、pメソッドを使用して、ARGV変数がターミナル上で指定した値を、配列として保持していることを確認します。
[サンプルコード]
p ARGV
[実行結果]
$ ruby argv.rb a r g v ["a", "r", "g", "v"]
以上のように、ARGVは配列であり、ターミナルで渡された値を保持しています。あとは、Rubyスクリプトの中で、好きな時にARGVから値を取り出して、データとして使用できます。
whileとgets、lineで入力ループ
getsは標準入力から1行しか入力できませんでした。
しかし、whileを用いることで、標準入力からCTRL+D(あるいはCTRL+Z)が入力されるまでの入力を、1行ずつですが、止まらずに続けて受け取ることができるようになります。
実際のサンプルコードをみてみましょう。なお、whileの条件式に
while lien = gets
と「line = gets」を指定しています。このことにより、代入演算子=の実行結果が、whileの条件式の値となります。
「=」の実行結果とは、変数lineへgetsの値を代入した後のlineの値のことです。通常getsは標準入力に入力されたキーボード入力を文字列として返します。
そして、入力の終わりを示すCTRL+D(あるいはCTRL+Z)が入力されたときは、getsはnilを返します。そのため、lineもnilになり、whileの条件式の値がnilとなり、whileループが終了します。
puts "何か入力してください。" while line = gets p line.chomp end
[実行結果]
何か入力してください。 hello "hello" good morning! "good morning!" see you! "see you!"
以上のように、whileループのおかげで、CTRL+D(あるいはCTRL+Z)が入力されるまで、繰り返しgetsで標準入力からキーボード入力を取得できます。
まとめ
いかがでしたでしょうか。ここでは、Rubyと標準入力の関係について、一通り解説してきました。
標準入力と言われると、すごく難しい概念のように構えてしまいそうですが、標準入力は難しく考えず、キーボードからの入力と考えれば、腑に落ちやすいのではないでしょうか。
学習のポイントを振り返ってみましょう。
- 標準入力とはキーボードからの入力のこと。
- Rubyで標準入力からキーボードの入力を取得するには、getsを使うと便利。
- getsで入力した文字列には改行コードが含まれているため、chomp!で改行コードだけ削除する。
- 標準入力から複数行を取得するには、readlinesを使用する。
- Rubyは標準入力オブジェクトを持っており、それは変数$stdin、定数STDINに格納されている
- $stdin、STDINをレシーバとして、gets、readlines、readなどが使用できる。
- コマンドラインの文字列は配列ARGVに格納されている。
- whileとgets、lineを使って、標準入力からのキーボード入力を何行でも取得できる。
使い方を忘れてしまったら、またこのページを確認してみてください。