Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2912

getoptions を使って面倒なシェルスクリプトのオプション解析コードを自動生成しよう!

$
0
0
はじめに 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 をインストールしておいて動的にオプションパーサーを生成するやり方なのですが、このようにジェネレータとして使用することもできるようになっています。 さいごに もういいかげんシェルスクリプトのオプション解析コードを試行錯誤して自分で書くのはやめませんか?

Viewing all articles
Browse latest Browse all 2912

Trending Articles