こんにちは。
シェルスクリプトの自力による引数処理(解析)を作りました1(arg_parse.sh)。テンプレートとして利用できると思います。
特徴
- ショートオプション名、ロングオプション名、複合フラグ2、引数付きオプションへ対処します。
- 誤った使い方を検出し安全に停止します。
- オプション引数解析部コード(
whileループ)の簡素化、およびUSAGE/Options(= helpメッセージ)内容と良好に対応するよう努めました。 - POSIX 準拠シェルで動きます。
制約条件
- オプション(およびその引数)は前半へ、位置引数(主引数)は後半へ固まっている必要があります。
-
''や""を引数付きオプションの引数として与えるには、空白区切り型(例:-m "")で指定する必要があります(シェルに認識させるためです)。 -
-で始まる文字列を引数付きオプションの引数として与えるには、密着型(例:-m"-xyz")で指定する必要があります。 -
-で始まる文字列を位置引数として与えるには、位置引数の始まりを明示した後(--)、それ以降に指定する必要があります(例:./arg_parse.sh -- -1 -2)。
動作例
DEBUG モード
$ dash arg_parse.sh -mdog -l9 1 2 3
$ dash arg_parse.sh -m dog -l 9 1 2 3
optional arguments:
-m: dog
-l: 9
positional arguments: 1 2 3
ロングオプション名で動かした例
$ dash arg_parse.sh --mammal cat --loops 9 I II III
$ dash arg_parse.sh --mammal=cat --loops=9 I II III
optional arguments:
-m: cat
-l: 9
positional arguments: I II III
誤った使い方の検出例
$ dash arg_parse.sh --loops -xy
Warning: Type "arg_parse.sh --help" for usage instructions.
- Option '--loops' requires an argument
- Unknown option: '-x'
- Unknown option: '-y'
help オプションでの動作例
$ dash arg_parse.sh --help
Name: arg_parse.sh - parse arguments
Usage: arg_parse.sh [options] [positinal_argument [...]]
Options:
-h|--help Show this usage and exit.
-d|--debug Enable debug mode.
-l|--loops N Set the number of loops (default: 1)
-m|--mammal NAME Set mammal name.
Source code
説明
-
whileループは、位置パラメータをshiftしながら、オプション引数を先頭順に取り出します。 -
extract_opt_value_f(内部関数)は、 引数つきオプション(+引数)から、その引数部分を取り出します(動作例では-m|--mammalなどの直後の値)。- 加えて
whileループで使うためのshift数を求めます。
- 加えて
-
他の部分はエラー処理・メッセージ出力などのためのコードです。
解析部コードを機械的に生成
USAGE/Options(helpメッセージ)の記述は、オプション引数解析部(whileループ)のコードと対応させており、率直に解析部コードを記述できています。
さらにはその記述から機械的にコードを生成できそうで、やってみました。例えば、
-h|--help
-d|--debug
-l|--loops N
-m|--mammal NAME
を与えると下記が生成されます3。
while [ $# -gt 0 ]; do
opt_token="$1"
case "$opt_token" in
-h|--help) help_enabled=$TRUE;;
-d|--debug) debug_enabled=$TRUE;;
-l*|--loops*) n_loops_var=$(extract_opt_value_f -l--loops "$@");;
-m*|--mammal*) name_mammal_var=$(extract_opt_value_f -m--mammal "$@");;
-[!-][!-]*) split_combined_option_global_f "$opt_token"; shift
set -- "$first_flag" "$rest_flags" "$@"; continue;;
--) shift; break;;
-*) append_warning_f "Unknown option: '$opt_token'";;
*) break;;
esac
shift_additional=$?
if [ $shift_additional -lt $EXTRACT_FAILED ]; then
shift $shift_additional # 0: default, 1: next arg by extract_opt_value_f
else
append_warning_f "Option '${opt_token%=}' requires an argument"
fi
shift
done