Subscribed unsubscribe Subscribe Subscribe

oinume journal

Scratchpad of what I learned

Shellでgetoptsを使ってコマンドライン引数の解析

だいぶ前の話、Perlを使わないでShellスクリプトで頑張っていた頃、Shellでコマンドラインオプションの解析をやる時は

 

#!/bin/sh

 

for OPT in $*

do

case $OPT in

'-x' )

FLAG_X="TRUE"

;;

'-y' )

shift

FLAG_Y="TRUE"

VALUE_Y=$1

;;

esac

 

shift

done

 

if [ "$FLAG_X" = "TRUE" ]; then

echo "Option -x specified."

fi

 

if [ "$FLAG_Y" = "TRUE" ]; then

echo "Option -y $VALUE_Y specified."

fi

 

という感じで $* と shift を使ってやっていたのですが、最近 getopts なる素敵なビルトインコマンドを知りました。これを使うと上のスクリプトは下のように書き直すことができます。

 

#!/bin/sh

 

while getopts xy: OPT

do

case $OPT in

"x" )

FLAG_X="TRUE"

;;

"y" )

FLAG_Y="TRUE"

VALUE_Y=$OPTARG

;;

esac

done

 

if [ "$FLAG_X" = "TRUE" ]; then

echo "Option -x specified."

fi

 

if [ "$FLAG_Y" = "TRUE" ]; then

echo "Option -y $VALUE_Y specified."

fi

 

 

スクリプトの行数自体はあんまり変わらないように見えますが、shift 忘れをよくやらかしていたので、それが無くなった分つまらないバグを入れ込まなくなった気がします。

 

getoptsの解説

getopts の引数にオプションの文字を指定しますが、文字のあとに : (コロン)をつけると、引数ありのオプションという扱いになります。さらに

 

$ ./getopts.sh -z

 

のように未定義のオプションを指定すると

 

/home/oinume/tmp/script/getopts.sh: illegal option -- z

 

というように怒られます。このエラーハンドリングを自前でやるには :xy: のように、getopts の引数の文字列の最初を : にすればいいみたい。

 

さらに $OPTIND という変数を下記のように -1 してやることで、オプション以降に与えられた引数を取得することができます。例えば、上のスクリプトに下記を足して

 

shift `expr $OPTIND - 1`

if [ -n "$1" ]; then

echo "Argument $1 specified."

fi

 

 

 

$ ~/tmp/script/getopts.sh -x -y yyy hoge

 

のように実行すると

 

 

Option -x specified.

Option -y yyy specified.

Argument hoge specified.

 

 

となります。getopts を実行すると、$OPTIND にはオプションのインデックス番号が保存されているので、これを -1 して shift してやることで、オプション以降の引数が取得できるようになるという仕組みです。

 

最近はこういうレベルのプログラムだったらPerlで書くことも多かったのですが、Shell でも十分いけそうだと実感しました。

 

[tmkm-amazon]4873112672[/tmkm-amazon]