${1:0:1}を使って最初の引数の最初の文字が「-」かどうかを判定したりするなど、直接自分でパースすることもできるが、自分でパースする場合には、与えられたオプションが何であるかとか、引数を取っているかどうかとかを確認するためにif/thenやcaseなどを使ったコードを自分でさらに書き足す必要があるだろう。
しかしそうしたところで、例えば、続けてその後に引数を指定する必要のあるオプションに対して必要な引数をユーザが与えなかった場合、あなたの自作のルーチンはどうなるのだろうか? あるいは「-ab」のように、ユーザが2つのオプションをまとめて指定してスクリプトを呼び出した場合は? そのような場合もうまくパースできるのだろうか? スクリプトにオプションが必要ということはよくあることなので、シェルスクリプトではオプションのパースが必要になることがよくある。オプションのパースを行なう、より標準的な方法はないのだろうか?
(本記事は最近出版された「 bash Cookbook 」からの抜粋。)
オプションのパースを行なう標準的な方法は、bashの組み込みコマンド「getopts」を使うことだ。以下に、getoptsのマニュアルページに載っている例を少しだけ改変したものを示す。
#!/usr/bin/env bash # cookbook filename: getopts_example # # using getopts # aflag= bflag= while getopts 'ab:' OPTION do case $OPTION in a) aflag=1 ;; b) bflag=1 bval="$OPTARG" ;; ?) printf "Usage: %s: [-a] [-b value] args\n" $(basename $0) >&2 exit 2 ;; esac done shift $(($OPTIND - 1)) if [ "$aflag" ] then printf "Option -a specified\n" fi if [ "$bflag" ] then printf 'Option -b "%s" specified\n' "$bval" fi printf "Remaining arguments are: %s\n" "$*"
この例では、2つのタイプのオプションがサポートされている。1つめのタイプのオプションは単純で、単独で使用され引数がないものだ。このタイプのオプションは通常、コマンドの動作を変更するフラグとなっている。例としてはlsコマンドの-lオプションなどがある。2つめのタイプのオプションは、引数が必要となるものだ。このタイプのオプションの例には、mysqlコマンドの-uオプション(「mysql -u sysadmin」などのようにしてユーザ名を与える)がある。それではgetoptsを使ってこの2つのタイプのオプションを使えるようにする方法を見ていこう。
getoptsを使用するためには2つの引数を与える必要がある。
getopts 'ab:' OPTION
最初の引数はオプションで使用する文字のリストであり、2つめの引数はシェル変数の名前だ。上記のシェルスクリプトの例では、有効なオプションとして-aと-bのみを定義しているので、getoptsの最初の引数には、それらの2文字(とコロン)だけが与えられている。ではコロンはどういう意味なのかというと、(例えば「-u ユーザ名 」や「-f ファイル名 」と同じような形で)-bに引数が必要であるということを示している。なおコロンは、引数を取る各オプション文字のすぐ隣に置く必要がある。したがって例えば引数を取るのが-aオプションだけの場合にはa:bとなる。
