bashの引数解析のひな形

# 背景

bashの組み込み関数`getopts`はlong name optionに対応していないので、不便なことがあるので、独自にひな形を作成してみたのでその記録です。

# 制約

* オプション値を複数指定できない。
* オプション値が"-"で始まる値を受付できない。
* オプション以外の引数よりも後にオプション指定ができない。（これは多くのコマンドと同じ仕様なので優先度「低」）

# ひな形

```shell:bash_param_format.sh
#!/bin/bash

# usagesに表示する名前です。ここではシェルのファイル名にしています。
PROGRA_NAME="$( basename $0 )"

# エラーメッセージを標準エラー出力に赤字で出力するための関数。
function output_error() {
    echo -e "\e[31m$@\e[m" >&2
}

# 値付きオプションについて、値が指定されていることとその値の妥当性をチェックします。
# $1がオプションの値で$2以降にその値の取りうる値を指定します。
function _check_opt_value() {
    local OPT_VALUE=$1
    local VALID_VALUES=${@:2} # 2番目以降の値配列
    # 空文字でないこと、次のオプションではない(=ハイフンで始まらない)というチェック（⇒ハイフンで始まるオプション値には対応してません。。。）
    if [[ -z "${OPT_VALUE}" ]] || [[ "${OPT_VALUE}" =~ ^-+ ]]; then
        output_error "option requires an argument --${OPT_NAME}."
        _usage
        exit 1
    fi
    # オプション値の妥当性をチェックします。
    if ! `echo "${VALID_VALUES}" | grep -q "${OPT_VALUE}"`; then
        output_error "option --${OPT_NAME} is invalid values.Allowd value is (${VALID_VALUES})"
        _usage
        exit 1
    fi
    return 0
}

# ヘルプ表示。（オプションの指定方法に不正があった場合にも出力）
function _usage() {
  cat << __EOF__

Usage:
  ${PROGRA_NAME} [-o|--optvalue value1|value2|value3] [-b|--boolean] [-h|--help] [ARGUMENTS]...

Description:
   Commnad description.

Options:
  -o --optvalue   Specify option with value. "valule1" or "valule2" or "value3". default is "valule1".
  -b --boolean    Specify boolean option.(Not specify is false)
  -h --help       Show help message.

__EOF__
}


# オプション値の初期値をここで定義する。
OPT_VALUE=value1
IS_BOOLEAN=false

# bashの組み込み関数`getopts`はlong nameオプションに対応してないので以下のように引数すべてループしてオプションを解析します。
while [ $# -gt 0 ]; do
    # 現在位置の引数からオプションの名前を抽出（先頭のハイフン1回or2回繰り返しは除去）
    OPT_NAME=$(echo $1 | sed 's/^-\{1,2\}//')
    case "${OPT_NAME}" in
        # "-o" or "--optvalue"の場合(正確には"--o"や"-optvalue"も許容するけど。。。)
        'o' | 'optvalue' )
            # "-o" or "--optvalue"の次の引数をオプションの値として抜粋
            OPT_VALUE=$2
            # オプションの値の妥当性をチェック
            _check_opt_value "${OPT_VALUE}" "value1" "value2" "value3"
            # "-o" or "--optvalue"とその値の分引数配列をシフトさせる。
            shift 2
            ;;
        'b' | 'boolean' )
            # "-b" or "--boolean"が指定されたフラグをONにする。
            IS_BOOLEAN=true
　　　　　　 # こっちはオプション値がないので１つだけ引数配列をシフトさせる。
            shift 1
            ;;
        'h' | 'help' )
            # ヘルプメッセージを表示して即終了。
            _usage
            exit 0
            ;;
        * )
            # ハイフンで始まる場合は不正なオプションとする。（ただし、引数自体をハイフンで始める値が受け付けられない問題があるけど）
            if [[ "$1" =~ ^- ]]; then
                output_error "${PROGRA_NAME}: illegal option -- '${OPT_NAME}'"
                _usage
                exit 1
            fi
            break
            ;;
    esac
done

# オプションではない、コマンド自体の引数が１つ以上であることをチェックする。（必要hな場合のみ）
if [ $# -lt 1 ]; then
    output_error "Required arguments."
    _usage
    exit 1
fi

# ここ以下がメインプロセス。ここではオプションと引数の値を表示している。
idx=1
for ARG_VALUE in $@; do
    echo "ARGUMENT[${idx}]=${ARG_VALUE}"
    idx=$((idx + 1))
done
echo "OPT_VALUE=${OPT_VALUE}"
if "${IS_BOOLEAN}" ; then
    echo "Specified '-b' option"
fi

exit 0
```

# 使い方

### 例1) オプション指定なし

```shell-session
[user@hostname ~]$ ./bash_param_format.sh foo bar baz
ARGUMENT[1]=foo
ARGUMENT[2]=bar
ARGUMENT[3]=baz
OPT_VALUE=value1
```

### 例2) short optionオプション指定あり

```shell-session
[user@hostname ~]$ ./bash_param_format.sh -o value2 -b foo bar baz
ARGUMENT[1]=foo
ARGUMENT[2]=bar
ARGUMENT[3]=baz
OPT_VALUE=value2
Specified '-b' option
```

### 例3) long optionオプション指定あり

```shell-session
[user@hostname ~]$ ./bash_param_format.sh --optvalue value3 -boolean foo bar baz
ARGUMENT[1]=foo
ARGUMENT[2]=bar
ARGUMENT[3]=baz
OPT_VALUE=value2
Specified '-b' option
```

### 例4) オプションに不正な値を指定。

```shell-session
[user@hostname ~]$ ./bash_param_format.sh --optvalue hogehoge foo bar baz
option --optvalue is invalid values.Allowd value is (value1 value2 value3)

Usage:
  bash_param_format.sh [-o|--optvalue value1|value2|value3] [-b|--boolean] [-h|--help] [ARGUMENTS]...

Description:
   Commnad description.

Options:
  -o --optvalue   Specify option with value. "valule1" or "valule2" or "value3". default is "valule1".
  -b --boolean    Specify boolean option.(Not specify is false)
  -h --help       Show help message.

```

### 例5) 未対応のオプションを指定。

```shell-session
[user@hostname ~]$ ./bash_param_format.sh --unknowopt hoge foo bar baz
bash_param_format.sh: illegal option -- 'unknowopt'

Usage:
  bash_param_format.sh [-o|--optvalue value1|value2|value3] [-b|--boolean] [-h|--help] [ARGUMENTS]...

Description:
   Commnad description.

Options:
  -o --optvalue   Specify option with value. "valule1" or "valule2" or "value3". default is "valule1".
  -b --boolean    Specify boolean option.(Not specify is false)
  -h --help       Show help message.
```