Bashスクリプトオプションパラメータをオプションで作成できますか?

Bashスクリプトオプションパラメータをオプションで作成できますか?

これらの入力のいずれかが機能することを願っています。つまり、-nオプション自体はオプションです。私はすでにこれを行う方法を知っています。ただし、上部にオプションのパラメータがある可能性があります。引数が指定されない場合、代替値が適用されます。

command -n 100
command -n

電子入力タイプまたは後者のみが機能するようにすることはできますが、どちらも機能することはできません。

HAS_NICE_THINGS=0
NICE_THINGS=50       # default value.

while getopts n: option; do
#while getopts n option; do    # NICE_THINGS would always be that default value.
#while getopts nn: option; do    # same.
    case "${option}" in
    n)
        HAS_NICE_THINGS=1
        if [[ ! -z "${OPTARG}" ]] && (( "${OPTARG}" > 0 )) && (( "${OPTARG}" <= 100 )); then
            NICE_THINGS=${OPTARG}
        fi;;
    esac
done

# error message:
# option requires an argument -- n

私のスクリプトにブールが必要かどうかは完全にはわかりませんが、これまではもし備えてHAS_NICE_THINGS一つ( )を記録しています。

私の究極の目標は、最終的に画像を保存するときにJPG品質を設定することです。しかし、この構造が他の場所でも役に立つと思います。

私はとUbuntu 18.04.5を使用していますGNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

答え1

Bash / POSIXと比較してそれほどスマートではありませんが、getoptsutil-linuxまたはBusyboxで "enhancement"(sなし)を使用してgetoptこれを実行できます。 (それはすべてです。特に多くの「伝統的な」getopt実装も壊れているからです。空白も壊れています。)

マニュアルページには次のように表示されますgetopts

オプションの文字列認識するオプション文字が含まれています。文字の後にコロンが続く場合、オプションには引数が必要で、スペースで区切る必要があります。

オプションのオプションパラメータについては言及していません。

もちろん、デフォルト以外の値を提供する別のオプションオプションを使用することもできます。たとえば、-nパラメータを使用せずに良い機能のみを有効にし、パラメータを使用して-N <arg>良い機能を有効にし、値を設定します。

たとえば、次のようになります。

#!/bin/bash
HAS_NICE_THINGS=0
NICE_THINGS_VALUE=50
        
while getopts nN: option; do
    case "${option}" in
    n)
        HAS_NICE_THINGS=1
        shift;;
    N)
        HAS_NICE_THINGS=1
        NICE_THINGS_VALUE=$OPTARG
        shift; shift;;
    esac
done

if [ "$HAS_NICE_THINGS" = 1 ]; then
    echo "nice things enabled with value $NICE_THINGS_VALUE"
fi

減らす

$ bash nice-getotps.sh -n
nice things enabled with value 50
$ bash nice-getopts.sh -N42
nice things enabled with value 42

util-linuxはgetoptデュアルコロン構文を使用してオプションのオプションパラメータを取得します。使い方が少しぎこちなくて処理が必要ですevalが、正しく行うと正常に動作するようです。

マニュアルページ:

-o shortopts[...]の各短いオプション文字近道必須パラメータがあることを示すコロンと、オプションのパラメータがあることを示す2つのコロンが続くことがあります。

スクリプトを使用して元の値を印刷すると、正しく機能していることを確認できます(getopt-optional.sh)。

#!/bin/bash
getopt -T
if [ "$?" -ne 4 ]; then
    echo "wrong version of 'getopt' installed, exiting..." >&2
    exit 1
fi 
params="$(getopt -o an:: -- "$@")"
eval set -- "$params"
while [ "$#" -gt 0 ]; do
    case "$1" in
    -n)
        echo "option -n with arg '$2'"
        shift 2;;
    -a)
        echo "option -a"
        shift;;
    --) 
        shift
        break;;
     *) 
        echo "something else: '$1'"
        shift;;
    esac
done
echo "remaining arguments ($#):"
printf "<%s> " "$@"
echo

私達は得た

$ bash getopt-optional.sh -n -a
option -n with arg ''
option -a
remaining arguments (0):
<> 
$ bash getopt-optional.sh -n'blah blah' -a
 -n 'blah blah' -a --
option -n with arg 'blah blah'
option -a
remaining arguments (0):
<> 

-n空のパラメータとして表示するパラメータはありません。

いずれにせよ、明示的なnull引数を渡すことはできません。オプション引数は、オプション自体と同じコマンドライン引数内になければならず、-n引用符を削除した後の引数と同じでなければならないためです。これにより、オプションのオプション引数を使用するのが難しくなります。これは、オプション引数なしでオプションとして扱われ、オプションではなく一般的なコマンドライン引数が続くため、-n""使用する必要があるためです。これは、必須オプションパラメータを使用したときに発生するものとは異なります。-nx-n x-nx-n

詳しくはgetoptこちらこのStackoverflowの答え到着Bashでコマンドライン引数を解析する方法は?


getoptこれは、Linuxシステムでは一般的ですが、他のシステムでは一般的ではない可能性がある特定の実装に限定されているようです。他の実装では、getopt引数はスペースをサポートしない可能性があります(プログラムはスペースを引用符で囲む必要があります)。 「アップグレードされた」util-linuxバージョンには、特定のバージョンがインストールされて-Tいるかどうかをテストするオプションがあります。以下は、制限事項と注意事項の説明ですgetoptgetopt、getopts、または手動解析 - 短いオプションと長いオプションの両方をサポートするには何を使用する必要がありますか?

また、getoptこれは標準的なツールではありませんgetopts

答え2

-aオプションのオプションパラメータでオプションを提供するとします。オプションを使用すると、シェルにシェル変数を設定する必要がありますが、オプション引数が指定されていない場合は値に設定しa_opt、それ以外の場合は一般的な値に設定する必要があります。$a_default$OPTARG

パラメータなしで使用するタイミングを決定するには、-a2つのケースがあります。

  1. ユーザーが使用しているオプション引数がgetopts実際に他のオプションの1つであると思う
  2. この-aオプションはリストのコマンドラインの最後に使用されます(getoptsこの場合、通常は欠落しているオプションのエラーが生成されます)。

最初の状況は、$OPTARG他のオプションの1つに似ていることを確認することによって処理されます。その場合はデフォルト値を使用し、そうでない場合はデフォルト値を使用してください$OPTARG。デフォルトを使用する場合は、後でオプションの解析を再開する必要があります-a。これは、いくつかの引数(OPTINDそのうちの1つ)を削除して1にリセットしてから、位置引数リストの前に追加するOPTINDことを意味します。$OPTARG

-aこれが意味するのは、オプションの1つに見える引数を使用できないことです。

2番目のケースを処理する方法は、オプション文字列の最初の文字をgetoptsbeにすることです:。これには2つの効果があります。

  1. getoptsもはやそれ自体エラーは発生しません。
  2. オプション引数を必要とするオプションがオプション引数を取得できない場合は、オプション名がに置かれ、オプションで$OPTARG使用:されるオプション変数に配置されますgetopts

これは:、一般的に使用されるオプションの解析ステートメントにcaseケースを追加して、ユーザーがコマンドラインの最後にそのステートメントを使用したかどうかを$OPTARGテストできることを意味します。a-a

パスワード:

#!/usr/local/bin/bash

a_default='A default value'
d_opt=false

while getopts :a:b:c:d opt; do
        case $opt in
                a)
                        case $OPTARG in
                                -[a-d-]*)
                                        shift "$(( OPTIND - 1 ))"
                                        OPTIND=1
                                        set -- "$OPTARG" "$@"
                                        a_opt=$a_default
                                        ;;
                                *)
                                        a_opt=$OPTARG
                        esac
                        ;;

                b)      b_opt=$OPTARG ;;
                c)      c_opt=$OPTARG ;;
                d)      d_opt=true ;;

                :)
                        if [ "$OPTARG" = a ]; then
                                a_opt=$a_default
                        else
                                printf '%s: option requires an argument -- %s\n' \
                                        "$0" "$OPTARG" >&2
                                exit 1
                        fi
                        ;;

                *)      printf '%s: generic option parsing error\n' "$0" >&2
                        exit 1
        esac
done

shift "$(( OPTIND - 1 ))"

printf '%s = "%s"\n' \
        'a_opt' "${a_opt-(Not set)}" \
        'b_opt' "${b_opt-(Not set)}" \
        'c_opt' "${c_opt-(Not set)}" \
        'd_opt' "${d_opt-(Not set)}"

if [ "$#" -gt 0 ]; then
        printf 'Extra argument: "%s"\n' "$@"
fi

テスト:

a_opt-aオプションなしで使用するとデフォルト値が得られます。

$ ./script -a
a_opt = "A default value"
b_opt = "(Not set)"
c_opt = "(Not set)"
d_opt = "false"

a_opt-a使用しないと、次の値を取得できません。

$ ./script -b bval
a_opt = "(Not set)"
b_opt = "bval"
c_opt = "(Not set)"
d_opt = "false"

a_optoptions引数を指定して、通常どおりに値を指定できます-a

$ ./script -da aval -c cval
a_opt = "aval"
b_opt = "(Not set)"
c_opt = "cval"
d_opt = "true"

以下を使用してオプションの解析を終了できます--

$ ./script -d -a -- aval -c cval hello world
a_opt = "A default value"
b_opt = "(Not set)"
c_opt = "(Not set)"
d_opt = "true"
Extra argument: "aval"
Extra argument: "-c"
Extra argument: "cval"
Extra argument: "hello"
Extra argument: "world"

関連情報