κeenのHappy Hacκing Blog | Lispエイリアンの狂想曲

Shell Scriptでオプションをパースするときの必勝法

κeenです。CIMの解説 実装編の執筆はもうちょい掛かりそうです。だいたいコードが落ち着いたら書きます。

今回は長いオプションと短いオプションをシェルスクリプトでパースするときの話です。

シェルスクリプトではcaseを使う方法とgetoptsを使う方法があります。caseだと長いオプションと短いオプションを扱えるものの短いオプションをまとめるのに苦労し、getoptsだと短いオプションをまとめられるものの長いオプションを扱えません。

そこで解決策。--foo ARG -f ARG -hをパースし、他のオプションも許可(無視)、--でパースを止めるとします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while [ "$#" -gt 0 ];do
 ARG="$1";shift
 case "$ARG" in
 --foo) do_something_with "$ARG";;
 --) break;;
 --*) ;;
 -*)
 OPTIND=1
 while getopts :f:h OPT "$ARG"; do
 case "$OPT" in
 f) do_something_with "$OPTARG";;
 h) do_something;;
 esac
 done
 ;;
  
 esac
done

単純にcasegetoptsを組み合わせます。ポイントは-*)の節のOPTIND=1getoptsの第3引数でしょうか。

因みにこの例だと引数を消費します。引数を消費したくなければ

1
2
while [ "$#" -gt 0 ];do
 ARG="$1";shift

1
for ARG;do

に書き換えれば良く、--でパースを止めたくなければ--) break;;の節を無くせば良く、

他のオプションを許したくなければ--*);;の節を--*)exit 1;;などにし、getoptsの引数文字列:f:h:をとってgetopts fh ...とすれば良いです。

Written by κeen