工藤探偵事務所

Resarch and Investigation

ルビー3分クッキング 第十四回「コマンドライン引数」の巻

kudo-shunsaku2008-06-28




3分間で覚える Ruby のトピックスです。
でも、本家同様に実際には10分程度掛かります。

大事なのは小さな積み重ねと継続する才能ですね。
一番の怠け者の俺が言うのも変ですけどね。

第十四回は、「コマンドライン引数」の巻です。






前回、 UNIX コマンドになぞらえてちょっとだけ "cat" ぽいものを作ってみました。プログラム内で指定したファイルの中身をみるだけだったのですけどね。

折角ですからもう少しそれっぽくしたいと想います、つまり "cat.rb" をもう少しUNIXコマンドのそれらしく。今回はファイル名をコマンドラインから引数として受け取ることをやってみましょう。

まずはコマンドラインから引数として受け取る方法を確認しましょう。

Ruby では、スクリプトに続く引数は組み込み定数(及び組み込み変数)に格納されます。早速確認してみましょう。

ファイル名は、"argv.rb" などとして下さい。

# 組み込み変数に引数の文字列入ってます。
# 組み込み定数 ARGV の別名です。
puts $*
puts

puts $*[0] + " " + $*[1] + " " + $*[2] + " " + $*[3]
puts

# 組み込み定数にも引数の文字列入ってます。
# 組み込み変数 $* の別名です。
puts ARGV
puts

puts ARGV[0] + " " + ARGV[1] + " " + ARGV[2] + " " + ARGV[3]
puts

実行時、コンソール画面。

C:\rubycode\3minutes2cooking>ruby argv.rb beef chicken pork lamb
beef
chicken
pork
lamb

beef chicken pork lamb

beef
chicken
pork
lamb

beef chicken pork lamb

C:\rubycode\3minutes2cooking>

コマンドラインRuby スクリプト名に続く引数で渡した文字列がプログラム内で受け取れることが確認できました。

組み込み変数 "$*" もしくは組み込み定数 "ARGV" という配列が用意されています。これで引数リストでも個別の引数でも取り出すことができますね。但し、スクリプト名自体は含んでませんのでご注意下さい。

そうそ、現在の全引数リストが入っている組み込み変数の "$*" は、Bourne Shell(ボーンシェル, sh)と同じ変数名ですね。でも Bourne Shellでの個別の引数に対する "$1" は第1引数、... "$9" は第9引数、という使い方とは違いますね。それに Ruby では、$1, $2, ... $9 といった組み込み変数は別の意味に使われています。ご注意下さいませ。

ではコマンドラインから引数を受け取れることを確認しましたので、これを "cat.rb" に生かしましょう。コマンドラインから受け取る文字列をファイル名として処理するのです。

前回使用したのソースコード "cat.rb" を変更します。

#! ruby -Ks
# UNIX コマンドの cat を模倣してみます。
# 第弐版

# コマンドラインから指定されたレシピのファイル名
recipe = ARGV[0]
# puts "レシピは、" + recipe + " をひらきます。" # 確認です。

begin
    # レシピを開きます。
    file = open(recipe, "r")
    
    # レシピを読みます。
    while line = file.gets
        puts line
    end

# レシピが無かった時
rescue Errno::ENOENT => ex
    puts "お探しのレシピがありません。"
    puts "他のレシピをご覧下さいませ。"
    # puts ex.message
    
    # プログラムを中断します。
    exit 1
    
# その他の例外が起こった時
rescue => ex
    puts ex.message

ensure 
    # レシピを閉じます。
    file.close unless file.nil?
end

実行時、コンソール画面。

C:\rubycode\3minutes2cooking>ruby cat.rb beefstew_recipe.txt

『ビーフシチューのレシピ』

材料 :

* 牛肉(シチュー用で良い):適量(お好きなだけどうぞ)
     :
   (中略)
     :
9. 塩コショウで味を整え、器に盛ったら生クリームとパセリ(グリーンピースでも可)
をかけて完成です。

C:\rubycode\3minutes2cooking>
C:\rubycode\3minutes2cooking>ruby cat.rb porkcurry_recipe.txt

『ポークカレーライスのレシピ』

材料 :

* 豚肉:適量(お好きなだけどうぞ)
     :
   (中略)
     :
5. ルーをいれて弱火で20分程度煮て完成です。

C:\rubycode\3minutes2cooking>

レシピのファイル名をコマンドラインから取れるようになりました。これでプログラムの中にファイル名を埋め込まなくても、スクリプトを実行するときに指定できるようになりましたね。

お陰で別に用意しましたポークカレーのレシピも見れるようになりました。

さらに貪欲に複数のレシピ(ファイル)を一遍に表示できるようにしましょう。欲張り過ぎかな?

先ほどのソースコード "cat.rb" を変更します。

#! ruby -Ks
# UNIX コマンドの cat を模倣してみます。
# 第弐版

# レシピ(ファイル名)のリスト
ARGV.each { |recipe|
    # 順番に処理します。
    #puts "レシピは、" + recipe + " をひらきます。" # 確認です。
    
    begin
        # レシピを開きます
        file = open(recipe, "r")
        
        # レシピを読みます。
        while line = file.gets
            puts line
        end
        
    # レシピが無かった時
    rescue Errno::ENOENT => ex
        puts "お探しのレシピがありません。"
        puts "他のレシピをご覧下さいませ。"
        # puts ex.message
        
        # プログラムを中断します。
        exit 1
        
    # その他の例外が起こった時
    rescue => ex
        puts ex.message
        
    ensure 
        # レシピを閉じます。
        file.close unless file.nil?
    end
}

実行時、コンソール画面。

C:\rubycode\3minutes2cooking>ruby cat.rb beefstew_recipe.txt porkcurry_recipe.txt

『ビーフシチューのレシピ』

材料 :

* 牛肉(シチュー用で良い):適量(お好きなだけどうぞ)
     :
   (中略)
     :
9. 塩コショウで味を整え、器に盛ったら生クリームとパセリ(グリーンピースでも可)
をかけて完成です。


『ポークカレーライスのレシピ』

材料 :

* 豚肉:適量(お好きなだけどうぞ)
     :
   (中略)
     :
5. ルーをいれて弱火で20分程度煮て完成です。

C:\rubycode\3minutes2cooking>

UNIX コマンドの "cat" は『引数で指定されたファイルの内容を指定された順番に標準出力に書き出す』という、だらし無く、しまりがなくて、節度が無い、そんな機能が主要な機能なのです。大好きなコマンドです。

"cat" の名前の由来( "catenate" の略です)からも、本来はファイルを連結するという用途が主な気がしますが、実際はそれよりもだらだらと標準出力にファイルの内容を表示したりするために使われています。便利ですよ。

それを見事に Ruby で模倣できましたね。パチパチパチ(自分で拍手)。

今回は前回からの流れで「コマンドライン引数」を中心にお話しました。
目的は、"cat" コマンドに近づけという意気込みで改良してきました。本来の "cat" に近づくためには実はまだもうちょっと機能拡張しなければならないのですけど、気が向いたら次回続きをやりましょう。それよりファイルの操作の続きをやったほうが良いのかな?次回があればでお楽しみに。気長にお待ち下さいませ。



「おなかが鳴ると♪やってくる♪なかまを連れて♪やってくる♪」

今日はここまで。次回をお楽しみに。