はじめに
getoptions はシェルスクリプト用のオプションパーサーです。getopts や getopt の代わりに使うことができ、getoptions をインストールするだけで簡単にシェルスクリプトのオプション解析を実装することができます。しかし、不特定の人に配布するシェルスクリプトの場合は getoptions をインストールしてもらうというのは選択肢にならないかもしれません。
でも大丈夫! getoptions はオプションパーサーのジェネレータとして使うこともできます。ジェネレータとして使うと自分でオプションパーサーのコードを書く必要はありません。
オプションパーサーとしての使い方はこちら
「シェルスクリプト(bash等)の引数解析が究極的に簡単になりました」
使い方
対応するオプションの定義を書いた関数(parser_definition)とそれを認識するタグ(@getoptions ~ @end)と、オプションパーサーを生成するために必要なタグ(@gengetoptions parser -i parser_definition - ~ @end)を入れたシェルスクリプトを書きます。
#!/bin/sh
set -eu
# @getoptions
parser_definition() {
setup REST help:usage -- "Usage: example.sh [options]... [arguments]..." ''
msg -- 'Options:'
flag FLAG -f --flag -- "takes no arguments"
param PARAM -p --param -- "takes one argument"
option OPTION -o --option on:"default" -- "takes one optional argument"
disp :usage -h --help
disp VERSION --version
}
# @end
# @gengetoptions parser -i parser_definition -
# @end
# ここからメイン処理
echo "FLAG: $FLAG, PARAM: $PARAM, OPTION: $OPTION"
printf '%s\n' "$@" # rest arguments
以下のコマンドを実行すると、@gengetoptions ~ @end の中にオプションパーサーが生成されます。
gengetoptions embed --overwrite example.sh
生成コード
#!/bin/sh
set -eu
# @getoptions
parser_definition() {
setup REST help:usage -- "Usage: example.sh [options]... [arguments]..." ''
msg -- 'Options:'
flag FLAG -f --flag -- "takes no arguments"
param PARAM -p --param -- "takes one argument"
option OPTION -o --option on:"default" -- "takes one optional argument"
disp :usage -h --help
disp VERSION --version
}
# @end
# @gengetoptions parser -i parser_definition -
# Generated by getoptions (BEGIN)
# URL: https://github.com/ko1nksm/getoptions (v3.3.0)
FLAG=''
PARAM=''
OPTION=''
REST=''
getoptions_parse() {
OPTIND=$(($#+1))
while OPTARG= && [ $# -gt 0 ]; do
case $1 in
--?*=*) OPTARG=$1; shift
eval 'set -- "${OPTARG%%\=*}" "${OPTARG#*\=}"' ${1+'"$@"'}
;;
--no-*|--without-*) unset OPTARG ;;
-[po]?*) OPTARG=$1; shift
eval 'set -- "${OPTARG%"${OPTARG#??}"}" "${OPTARG#??}"' ${1+'"$@"'}
;;
-[fh]?*) OPTARG=$1; shift
eval 'set -- "${OPTARG%"${OPTARG#??}"}" -"${OPTARG#??}"' ${1+'"$@"'}
OPTARG= ;;
esac
case $1 in
'-f'|'--flag')
[ "${OPTARG:-}" ] && OPTARG=${OPTARG#*\=} && set "noarg" "$1" && break
eval '[ ${OPTARG+x} ] &&:' && OPTARG='1' || OPTARG=''
FLAG="$OPTARG"
;;
'-p'|'--param')
[ $# -le 1 ] && set "required" "$1" && break
OPTARG=$2
PARAM="$OPTARG"
shift ;;
'-o'|'--option')
set -- "$1" "$@"
[ ${OPTARG+x} ] && {
case $1 in --no-*|--without-*) set "noarg" "${1%%\=*}"; break; esac
[ "${OPTARG:-}" ] && { shift; OPTARG=$2; } || OPTARG='default'
} || OPTARG=''
OPTION="$OPTARG"
shift ;;
'-h'|'--help')
usage
exit 0 ;;
'--version')
echo "${VERSION}"
exit 0 ;;
--)
shift
while [ $# -gt 0 ]; do
REST="${REST} \"\${$(($OPTIND-$#))}\""
shift
done
break ;;
[-]?*) set "unknown" "$1"; break ;;
*)
REST="${REST} \"\${$(($OPTIND-$#))}\""
esac
shift
done
[ $# -eq 0 ] && { OPTIND=1; unset OPTARG; return 0; }
case $1 in
unknown) set "Unrecognized option: $2" "$@" ;;
noarg) set "Does not allow an argument: $2" "$@" ;;
required) set "Requires an argument: $2" "$@" ;;
pattern:*) set "Does not match the pattern (${1#*:}): $2" "$@" ;;
notcmd) set "Not a command: $2" "$@" ;;
*) set "Validation error ($1): $2" "$@"
esac
echo "$1" >&2
exit 1
}
usage() {
cat<<'GETOPTIONSHERE'
Usage: example.sh [options]... [arguments]...
Options:
-f, --flag takes no arguments
-p, --param PARAM takes one argument
-o, --option[=OPTION] takes one optional argument
-h, --help
--version
GETOPTIONSHERE
}
eval getoptions_parse ${1+'"$@"'}; eval set -- "${REST}"
# Generated by getoptions (END)
# @end
# ここからメイン処理
echo "FLAG: $FLAG, PARAM: $PARAM, OPTION: $OPTION"
printf '%s\n' "$@" # rest arguments
生成されるコードは見ての通り比較的シンプルなコード(おそらく手動で書くのと大差ない)です。外部コマンド呼び出しもヘルプを表示するときに cat を使うだけなので高速です。bash だけではなく dash などを含め POSIX シェル全てに対応しています。オプションを変更するときは parser_definition 関数の中身を変更してもう一度生成するだけです。
推奨する使い方は getoptions をインストールしておいて動的にオプションパーサーを生成するやり方なのですが、このようにジェネレータとして使用することもできるようになっています。
さいごに
もういいかげんシェルスクリプトのオプション解析コードを試行錯誤して自分で書くのはやめませんか?
↧