シェルスクリプトで一つのオプションに対して複数の引数を持たせるような方法を探したんですが、みつからなかったので私の考えた方法を紹介します。
getoptsコマンドではオプションの引数は一つしか扱うことができないため、
./test.sh -r 100 200 -c abc def
のように一つのオプションに対して引数を複数個持たせることはできません。
複数の引数を持つオプションを可能にするためには自分でオプションを取得する関数を作成する必要があります。
以下は私が作成した複数の引数を持つオプションを扱えるgetoptx関数を利用して、オプションの引数をすべて表示するようにしたスクリプトです。
#!/bin/bash
getoptx(){
div="=div="
space="=space="
ARGS=$@
ARGS=`echo ${ARGS// /$space}|sed -e "s/\-/${div}/g"`
OPTS=(${ARGS//$div/ })
itr_i=0
while test $itr_i -lt ${#OPTS[*]};do
OPT=(${OPTS[$itr_i]//$space/ })
#${OPT[1]}に一つ目の引数、${OPT[2]}に二つ目の引数が格納されている
case ${OPT[0]} in
r)
#rオプションの処理
echo ${OPT[1]}" "${OPT[2]}
;;
c)
#cオプションの処理
echo ${OPT[1]}" "${OPT[2]}
;;
\?)
#例外オプションの処理
exit 1
;;
esac
itr_i=`expr $itr_i + 1`
done
}
getoptx $@
このスクリプトのファイル名をtest.shとした場合、
./test.sh -r 100 200 -c abc def
と実行すると
100 200
abc def
と出力されます。
このように、すべての引数を取得することができるので一つのオプションに対して複数の引数を持たせることが可能になりました。
では、関数の中身を説明します。
div="=div="
space="=space="
ARGS=$@
まず、divという変数はオプションを分けるディバイダーとなる文字列で、spaceという変数はスペースを一時的に保存しておくためにスペースと置き換えるための文字列です。
変数ARGSには$@を利用してこの関数に与えられた引数をすべて格納させています。
ARGS="-r 100 200 -c abc def"
となります。
次に、
ARGS=`echo ${ARGS// /$space}|sed -e "s/\-/${div}/g"`
OPTS=(${ARGS//$div/ })
ですが、ARGSのスペースを一時的に違う文字列に置き換えておかなければなりません。なぜなら、次の配列OPTSをオプションごとに引数ごと分割して格納した配列にしたいからです。配列を作る時に()で囲むようにするとスペースで分割されるので、スペースをそのままにしておくと、オプションの-rとその引数の100、100がそれぞれ別々に格納されてしまいます。
そのため、スペースを変数spaceで一時的に置き換え、これを防ぎます。
echo ${ARGS// /$space}
これを|(パイプ)でsedコマンドに繋げます。sedコマンドも文字列置換のコマンドです。
sed -e "s/\-/${div}/g"
-eのあとにある条件はすべての文字-を変数divで置換するということを意味しています。
ここで、
ARGS="=div=r=space=100=space=200=space==div=c=space=abc=space=def"
となりました。
OPTS=(${ARGS//$div/ })
はARGSのディバイダーをスペースで置き換えてから、そのスペース区切りで配列OPTSに文字列を格納していきます。
ここで、
OPTS=("r=space=100=space=200=space=" "c=space=abc=space=def")
となっています。オプションごとに分割することができました。
あとはwhileでこの配列分ループさせて、オプションとそれぞれの引数を分離します。whileの中の
OPT=(${OPTS[$itr_i]//$space/ })
は変数spaceをスペースで置換して、そのスペース区切りで配列OPTに文字列を格納しています。
itr_i=0
だった場合は、
OPT=("r" "200" "100")
となります。
あとはcase文でOPT[0]で何のオプションか判断して、処理を分けるだけです。
一つのオプションで複数の引数を持たせることが可能になると、例えば画像解像度を指定するときなんかは縦と横の大きさを一つのオプションで与えることができるようになるので非常に便利です。