2010年9月19日日曜日

オプション解析 (getoptsとgetoptの使い分け)

この話題はきっとポピュラーで、ネット上に多数の情報があるものと思いますが、、、

これまで、bash スクリプトでオプション解析をする際には、bash 組み込みコマンドのgetopts を使っていて、それで十二分と思っていました。しかし、getopts だと、コマンドラインの後半でオプションを指定できないことに気がつきました。 具体的には、

Usage: command.bash [-a] [-d dir] item1 item2 ...

のような構文の場合に、-d dir を item の後ろに指定しても、認識されません。(もちろん、工夫すればできそうではありますが)

そこで、調べたところ、外部コマンドの getopt なら期待通り処理してくれることを知りました。自分の中の整理のため、テンプレートを作りました。

まずは、getopts 版。いつもこのパターンを使ってました。
#!/bin/bash
#
# getopts-template.bash (use builtin getopts)
#
export LANG=C
usage_exit() {
        echo "Usage: getopts-template.bash [-a] [-d dir] item1 item2 ..." 1>&2
        exit 1
}
#
# Options
#
echo "$@"       ####DEBUG
while getopts ":ad:h" GETOPTS
do
  case $GETOPTS in
  a)    A_FLAG=yes
        ;;
  d)    OUTDIR=$OPTARG
        ;;
  h)    usage_exit
        ;;
  *)    usage_exit
        ;;
  esac
done
#
shift $((OPTIND - 1))
#
echo \$#=$#             ####DEBUG
echo \$@="$@"           ####DEBUG
echo A_FLAG=$A_FLAG     ####DEBUG
echo OUTDIR=$OUTDIR     ####DEBUG
次に、getopt 版です。
#!/bin/bash
#
# getopt-template.bash (use getopt utility)
#
export LANG=C
usage_exit() {
        echo "Usage: getopt-template.bash [-a] [-d dir] item1 item2 ..." 1>&2
        exit 1
}
#
# Options
#
echo "$@"       ####DEBUG
GETOPT=`getopt -q -o ad:h -- "$@"` ; [ $? != 0 ] && usage_exit
eval set -- "$GETOPT"
echo "$@"       ####DEBUG
while true
do
  case $1 in
  -a)   A_FLAG=yes      ; shift
        ;;
  -d)   OUTDIR=$2       ; shift 2
        ;;
  -h)   usage_exit
        ;;
  --)   shift ; break
        ;;
  *)    usage_exit
        ;;
  esac
done
#
echo \$#=$#             ####DEBUG
echo \$@="$@"           ####DEBUG
echo A_FLAG=$A_FLAG     ####DEBUG
echo OUTDIR=$OUTDIR     ####DEBUG
こちらの、getopt 版であれば、次のように -d オプションの指定を後半に行うことができます。
# ./getopt-template.bash item1 item2 -d dir
item1 item2 -d dir
-d dir -- item1 item2
$#=2
$@=item1 item2
A_FLAG=
OUTDIR=dir
一方、getopts の場合には、次のようになってしまいます。
# ./getopts-template.bash item1 item2 -d dir
item1 item2 -d dir
$#=4
$@=item1 item2 -d dir
A_FLAG=
OUTDIR=

2010-09-25追記
まとめを書き忘れていました。getopts のほうがスッキリすると思うので、itemが不要な場合(将来も不要かどうかも一考はしつつ)は、getoptsで書き、item 指定がある構文を使う場合には、getopt を使う。というガイドラインでやっていこうと思います。

2011-02-13追記
下記も参照ください。ロングオプションの場合です。
getoptによるロングオプション解析

2011-08-31追記
perl の場合についても書きましたので、興味があるようでしたら、参照ください。
perl でオプション解析

2012-05-20追記
Python の場合についても書きました。
Python でオプション解析

0 件のコメント:

コメントを投稿

人気ブログランキングへ にほんブログ村 IT技術ブログへ