LoginSignup
81
73

More than 5 years have passed since last update.

OptionParser よりも指定が楽な ARGV.getopts のオプション指定(ロング/ショートも)

Last updated at Posted at 2014-08-04

まとめ

Ruby スクリプトの引数を ARGV だけで指定するのは簡便ですが、どの位置の引数が何に対応するのか直ぐに忘れてしまいますし、引数の省略も出来ないので面倒です。
標準ライブラリの OptionParser を使うのが手っ取り早いのですが、指定を詳細にしておかないといけないのがやはり面倒です。
で、楽なのが ARGV.getopts です。引数が Hash で返ってきます。しかも --help で受け付ける引数を表示させることも簡単にできます。
ARGV.getopts の使い方、特にショートネーム・ロングネームのオプション指定についてまとめました。

1.ショートとロングと別々に

getoptstest.rb
require 'optparse'
params = ARGV.getopts('abc:d:AB:C', 'alpha', 'brabo:', 'charlie:', 'delta:delta')
p params
$ ruby getoptstest.rb -a -don --charlie Check
{"a"=>true, "b"=>false, "c"=>nil, "d"=>"on", "A"=>false, "B"=>nil, "C"=>false, "alpha"=>false, "brabo"=>nil, "charlie"=>"Check", "delta"=>"delta"}
  • ARGV.getopts の第1引数がショートネームの指定、それ以降がロングネームの指定です。
  • キーはシンボルではなく文字列です。シンボルにしたい場合には ARGV.getopts(…) の部分を Hash[ARGV.getopts(…).map { |k, v| [k.to_sym, v] }] としましょう。
  • ショートの各文字に : を付けると引数を取ります。大文字と小文字は別扱いです。
  • ロングでも末尾に : を付けると引数を取ります。ロングはデフォルト値を取ることが出来ます。
  • 引数に --help を渡すと簡単なヘルプ画面が返されます。引数が必要な場合には VAL と表示されます。
$ ruby getoptstest.rb --help
Usage: getoptstest [options]
    -a
    -b
    -c VAL
    -d VAL
    -A
    -B VAL
    -C
        --alpha
        --brabo VAL
        --charlie VAL
        --delta VAL
  • なお、引数を取らないオプションは boolean なので値は true / false になります。
  • 引数を取るオプションは指定しないと値が nil になります。また、オプションを指定したときに引数を付けないと OptionParser::MissingArgument エラーになります。
$ ruby getoptstest.rb -a -c
getoptstest.rb:2:in `<main>': missing argument: -c (OptionParser::MissingArgument)

オプション名の一部でも指定可能

getoptstest_.rb
require 'optparse'
params = ARGV.getopts('abc:d:AB:C', 'alice', 'alpha', 'brabo:', 'charlie:', 'delta:delta')
p params
  • オプション指定をロングの形式 -- にした場合、オプションの全ての名称を指定しなくても、他のオプションと判別できれば指定を行うことが出来ます。 getoptstest_.rb の場合、 alicealpha とは3文字目で判別できますので、 alpalpha を指定していると判断してくれます。
$ ruby getoptstest_.rb --alp
{"a"=>false, "b"=>false, "c"=>nil, "d"=>nil, "A"=>false, "B"=>nil, "C"=>false, "alice"=>false, "alpha"=>true, "brabo"=>nil, "charlie"=>nil, "delta"=>"delta"}

判別出来ない場合には OptionParser::AmbiguousOption エラーになります。

$ ruby getoptstest_.rb --al
getoptstest_.rb:2:in `<main>': ambiguous option: --al (OptionParser::AmbiguousOption)

2.ロングの1文字目をショート形式で指定

  • ARGV.getopts の第1引数がショートの指定なので、ロングの形式のオプションの冒頭文字と衝突しない場合には、オプションの冒頭文字でオプションが指定できます。第1引数を空文字にしても問題なしです。
getoptstest2.rb
require 'optparse'
params = ARGV.getopts('z', 'Alpha', 'brabo:', 'charlie:', 'delta:delta')
p params
$ ruby getoptstest2.rb --help
Usage: getoptstest2 [options]
    -z
        --Alpha
        --brabo VAL
        --charlie VAL
        --delta VAL
$ ruby getoptstest2.rb -ac Check
{"z"=>false, "Alpha"=>true, "brabo"=>nil, "charlie"=>"Check", "delta"=>"delta"}
  • ショートの形式なので、以下のようにオプションと引数との間の空白を省略した書式でも同じ結果が返ります。
$ ruby getoptstest2.rb -acCheck
{"z"=>false, "Alpha"=>true, "brabo"=>nil, "charlie"=>"Check", "delta"=>"delta"}
$ ruby getoptstest2.rb -a -cCheck
{"z"=>false, "Alpha"=>true, "brabo"=>nil, "charlie"=>"Check", "delta"=>"delta"}
  • ショートの形式で指定できるのは小文字のみです。ロングで冒頭が大文字であってもショートの形式の場合には小文字で指定します。大文字にすると OptionParser::InvalidOption エラーになります。
$ ruby getoptstest2.rb -A -cCheck
getoptstest2.rb:2:in `<main>': invalid option: -A (OptionParser::InvalidOption)
  • ショートの指定が大文字であれば、ショートの指定と同じアルファベットの小文字でロングのオプションを指定することが出来ます。
getoptstest2_.rb
require 'optparse'
params = ARGV.getopts('AB', 'alpha', 'brabo:', 'charlie:', 'delta:delta')
p params
$ ruby getoptstest2_.rb -a
{"A"=>false, "B"=>false, "alpha"=>true, "brabo"=>nil, "charlie"=>nil, "delta"=>"delta"}
$ ruby getoptstest2_.rb -A
{"A"=>true, "B"=>false, "alpha"=>false, "brabo"=>nil, "charlie"=>nil, "delta"=>"delta"}
$ ruby getoptstest2_.rb -Aa
{"A"=>true, "B"=>false, "alpha"=>true, "brabo"=>nil, "charlie"=>nil, "delta"=>"delta"}
$ ruby getoptstest2_.rb -aA
{"A"=>true, "B"=>false, "alpha"=>true, "brabo"=>nil, "charlie"=>nil, "delta"=>"delta"}

3.ロングの1文字目が同じ場合

getoptstest3.rb
require 'optparse'
params = ARGV.getopts('', 'alice', 'alpha', 'brabo:', 'charlie:', 'delta:delta')
p params
$ ruby getoptstest3.rb --alice
{"alice"=>true, "alpha"=>false, "brabo"=>nil, "charlie"=>nil, "delta"=>"delta"}

1文字目が同じ場合に、冒頭文字のショート形式でその文字を指定した場合には、どちらのオプションであるのか不明であるとして OptionParser::AmbiguousOption エラーになります。

$ ruby getoptstest3.rb -a
getoptstest3.rb:2:in `<main>': ambiguous option: -a (OptionParser::AmbiguousOption)

返ってくる Hash の key を Symbol にしたい

params.inject({}) { |hash,(k,v)| hash[k.to_sym] = v; hash }

Symbol の key になります。
(参考:ruby - Best way to convert strings to symbols in hash - Stack Overflow
もちろん、一気にやっても問題ありません。

getoptstest.rb
require 'optparse'
params = ARGV.getopts('abc:d:AB:C', 'alpha', 'brabo:', 'charlie:', 'delta:delta').inject({}) { |hash,(k,v)| hash[k.to_sym] = v; hash }
p params
$ ruby etc/getoptstest.rb -a -don --charlie Check
{:a=>true, :b=>false, :c=>nil, :d=>"on", :A=>false, :B=>nil, :C=>false, :alpha=>false, :brabo=>nil, :charlie=>"Check", :delta=>"delta"}

引用・解説など(だらだらとw)

Ruby でスクリプトに渡される引数配列 ARGVOptionParser を扱うのは…いろいろ準備が面倒です。
で、簡単にする方法については先人が Qiita にいろいろと投稿してくださっています。
1.

require 'optparse'
params = ARGV.getopts('abc:')
p params
% ./its_the_ruby_way.rb -a -c /tmp/file
{"a"=>true, "b"=>false, "c"=>"/tmp/file"}
% ./its_the_ruby_way.rb -h
Usage: its_the_ruby_way [options]
    -a
    -b
    -c VAL

長いオプションも使いたいんだけど

require 'optparse'
params = ARGV.getopts('abc:', 'alpha', 'brabo', 'charlie:/tmp/default_file')
p params
% ./its_the_ruby_way.rb --alpha -c /tmp/hoge
{"a"=>false, "b"=>false, "c"=>"/tmp/hoge", "alpha"=>true, "brabo"=>false, "charlie"=>"/tmp/default_file"}

長い版のオプション(‘--charlie’)には、デフォルト値も指定できます。

コメント欄:長いオプションの省略

require 'optparse'
params = ARGV.getopts('', 'alpha', 'brabo', 'charlie:/tmp/default_file')
p params
./argv.rb -ab -c hoge
{"alpha"=>true, "brabo"=>true, "charlie"=>"hoge"}

Ruby - ARGVの処理にOptionParserを使ってるライバルをバックミラーから高速に消し去るARGV.getoptsの使い方 - Qiita

2.

require "optparse"
options = ARGV.getopts("", "dry-run")
p options

実行結果

$ ruby temp.rb --dry-run
{"dry-run"=>true}
$ ruby temp.rb
{"dry-run"=>false}

Rubyのoptparseを軽く使うなら悩む必要なんてなかった - Qiita

るりまも見てみる

ARGV の機能

optparserequire すると ARGVOptionParser::Arguable の機能 が加わります。以下の書き方ができるようになります。 OptionParser::Arguable#getopts はオプションを保持した Hash を返します。
library optparse

ロングとショートの区別はどこで

るりまにちゃんと書いてありました。

instance method OptionParser::Arguable#getopts

getopts(short_opt, *long_opt) -> Hash
指定された short_opt や long_opt に応じて自身をパースし、結果を Hash として返します。
コマンドラインに - もしくは -- を指定した場合、それ以降の解析を行ないません。
[PARAM] short_opt:
ショートネームのオプション(-f や -fx)を文字列で指定します。オプションが -f と -x の 2つの場合は "fx" の様に指定します。ここでオプションがないときは空文字列を指定します。 オプションが引数をとる場合は直後に ":" を付けます。
[PARAM] long_opt:
ロングネームのオプション(--version や --bufsize=512)を文字列で指定をします。 オプションが引数をとる場合は後ろに ":" を付けます。 オプションの引数のデフォルト値を ":" の直後に指定することができます。 例えば、"bufsize:1024" となります。
[EXCEPTION] OptionParser::ParseError:
自身のパースに失敗した場合、発生します。 実際は OptionParser::ParseError のサブクラスの例外になります。
例:

# t.rb の内容
require 'optparse'
params = ARGV.getopts("ab:", "foo", "bar:", "bufsize:1024")
p params
# 実行結果
$ ruby t.rb -b 1 --foo  --bar xxx -- -a
{"bufsize"=>"1024", "a"=>false, "b"=>"1", "foo"=>true, "bar"=>"xxx"}  # "a"=>false であることに注意。

instance method OptionParser::Arguable#getopts

この OptionParser::Arguable モジュールは require 'optparse' により ARGV に extend されます。ですので、 ARGV.getoptsOptionParser::Arguable#getopts を使うことが出来ます。

81
73
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
81
73