33

スクリプトで必須フラグとオプション フラグの両方を受け入れられるようにしたいと考えています。これが私がこれまでに持っているものです。

#!bin/bash

while getopts ":a:b:cdef" opt; do
      case $opt in
        a ) APPLE="$OPTARG";;
        b ) BANANA="$OPTARG";;
        c ) CHERRY="$OPTARG";;
        d ) DFRUIT="$OPTARG";;
        e ) EGGPLANT="$OPTARG";;
        f ) FIG="$OPTARG";;
        \?) echo "Invalid option: -"$OPTARG"" >&2
            exit 1;;
        : ) echo "Option -"$OPTARG" requires an argument." >&2
            exit 1;;
      esac
    done
echo "Apple is "$APPLE""
echo "Banana is "$BANANA""
echo "Cherry is "$CHERRY""
echo "Dfruit is "$DFRUIT""
echo "Eggplant is "$EGGPLANT""
echo "Fig is "$FIG""

ただし、次の出力:

bash script.sh -a apple -b banana -c cherry -d dfruit -e eggplant -f fig

...これを出力します:

Apple is apple
Banana is banana
Cherry is 
Dfruit is 
Eggplant is 
Fig is

ご覧のとおり、必須フラグの場合とは異なり、オプションのフラグは $OPTARG で引数を取得していません。きちんとした ":)" エラー処理を取り除くことなく、オプションのフラグで $OPTARG を読み取る方法はありますか?

=======================================

編集:以下のギルバートのアドバイスに従って終了しました。これが私がしたことです:

#!/bin/bash

  if [[ "$1" =~ ^((-{1,2})([Hh]$|[Hh][Ee][Ll][Pp])|)$ ]]; then
    print_usage; exit 1
  else
    while [[ $# -gt 0 ]]; do
      opt="$1"
      shift;
      current_arg="$1"
      if [[ "$current_arg" =~ ^-{1,2}.* ]]; then
        echo "WARNING: You may have left an argument blank. Double check your command." 
      fi
      case "$opt" in
        "-a"|"--apple"      ) APPLE="$1"; shift;;
        "-b"|"--banana"     ) BANANA="$1"; shift;;
        "-c"|"--cherry"     ) CHERRY="$1"; shift;;
        "-d"|"--dfruit"     ) DFRUIT="$1"; shift;;
        "-e"|"--eggplant"   ) EGGPLANT="$1"; shift;;
        "-f"|"--fig"        ) FIG="$1"; shift;;
        *                   ) echo "ERROR: Invalid option: \""$opt"\"" >&2
                              exit 1;;
      esac
    done
  fi

  if [[ "$APPLE" == "" || "$BANANA" == "" ]]; then
    echo "ERROR: Options -a and -b require arguments." >&2
    exit 1
  fi

どうもありがとう、みんな。これはこれまでのところ完全に機能します。

4

6 に答える 6

61

:「必須の引数」ではなく、「引数を取る」を意味します。つまり、オプション文字が後に続かないオプション文字は:、フラグ形式のオプション (引数なし) を意味し、オプション文字が後に続くオプション文字は:、引数付きのオプションを意味します。

したがって、おそらく

getopts "a:b:c:d:e:f:" opt

「必須」オプション (少し矛盾した表現) が必要な場合は、引数の解析後に、必須オプションの値がすべて設定されていることを確認できます。

于 2013-08-24T01:40:10.707 に答える
8

getopts簡単ではありません...「オプションの」オプション引数は、知る限り、実際には必須でなければなりません。もちろん、オプションの引数は、スクリプトへのオプションと同じ引数の一部である必要があります。そうしない-fと、オプションの引数を持つオプション-aと必須の引数を持つオプションが混乱する可能性があります。

# Is -a an option or an argument?
./script.sh -f -a foo

# -a is definitely an argument
./script.sh -f-a foo

これを行う唯一の方法は、オプションとその引数がスクリプトの同じ引数にあるかどうかをテストすることです。その場合、OPTARG はオプションの引数です。それ以外の場合、OPTIND を 1 減らす必要があります。もちろん、オプションには引数が必要になりました。つまり、オプションに引数がない場合に文字が検出されます。別のオプションを使用caseして、オプションが必要かどうかを判断してください。

while getopts ":a:b:c:d:e:f:" opt; do
    case $opt in
        a) APPLE="$OPTARG";;
        b) BANANA="$OPTARG";;
        c|d|e|f)
            if test "$OPTARG" = "$(eval echo '$'$((OPTIND - 1)))"; then
                OPTIND=$((OPTIND - 1))
            else
                 case $opt in
                     c) CHERRY="$OPTARG";;
                     d) DFRUIT="$OPTARG";;
                     ...
                esac
            fi ;;
        \?) ... ;;
        :)
             case "$OPTARG" in
                 c|d|e|f) ;; # Ignore missing arguments
                 *) echo "option requires an argument -- $OPTARG" >&2 ;;
            esac ;;
        esac
    done

これはこれまでのところうまくいきました。

于 2013-08-24T02:51:21.870 に答える
7

bash の場合、これは cli 引数を解析/サポートする私のお気に入りの方法です。私は getopts を使用しましたが、長いオプションがサポートされないのは非常にイライラしました。特に組み込み機能の場合はそうです。

usage()
{
    echo "usage: $0 -OPT1 <opt1_arg> -OPT2"
}
while [ "`echo $1 | cut -c1`" = "-" ]
do
    case "$1" in
        -OPT1)
                OPT1_ARGV=$2
                OPT1_BOOL=1
                shift 2
            ;;
        -OPT2)
                OPT2_BOOL=1
                shift 1
            ;;
        *)
                usage
                exit 1
            ;;
esac
done

短く、シンプル。エンジニアの強い味方!

これは、「--」オプションもサポートするように変更できると思います...

乾杯 =)

于 2014-02-03T18:42:36.187 に答える
6

ほとんどのシェル getopts は、オプションの引数がサポートされていないなど、長い間私を悩ませてきました。

ただし、「--posix」スタイルの引数を使用する場合は、$@ の引数の bash 引数ケースにアクセスしてください。

于 2013-08-24T01:45:41.910 に答える
5

bashの理解getopts

bashマニュアルページ(バージョン4.1マニュアルを引用)にgetoptsは次のように書かれています:

getopts optstring name[args]

getopts位置パラメータを解析するためにシェルスクリプトによって使用されます。optstringには、認識されるオプション文字が含まれています。文字の後にコロンが続く場合、オプションには引数が必要であり、空白で区切る必要があります。コロン (':') と疑問符 ('?') はオプション文字として使用できません。呼び出されるたびgetoptsに、シェル変数nameに次のオプションを配置し、名前が存在しない場合は初期化し、変数に処理される次の引数のインデックスを配置しますOPTINDOPTIND シェルまたはシェル スクリプトが呼び出されるたびに 1 に初期化されます。オプションに引数が必要な場合、getoptsその引数を変数に入れます OPTARG. OPTINDシェルは自動的にリセットされません。getopts新しいパラメーターのセットを使用する場合は、同じシェル呼び出し内での複数の呼び出しの間に手動でリセットする必要があります。

オプションの終わりにgetopts到達すると、ゼロより大きい戻り値で終了します。OPTINDは最初の非オプション引数のインデックスに設定され、nameは '?' に設定されます。

getopts通常は位置パラメータを解析しますが、 argsにさらに引数が指定されている場合getoptsは、代わりにそれらを解析します。

getopts2 つの方法でエラーを報告できます。optstringの最初の文字がコロンの場合、サイレント エラー レポートが使用されます。通常の操作では、無効なオプションまたは欠落しているオプション引数が検出されると、診断メッセージが出力されます。変数が 0 に設定されている場合、 optstringOPTERRの最初の文字がコロンでなくても、エラー メッセージは表示されません。

無効なオプションが見つかった場合は、getopts'?' を配置します。サイレントでない場合は、エラー メッセージを出力し、 unsets を出力しますOPTARGgetoptsが無音の場合、見つかったオプション文字が挿入されOPTARG、診断メッセージは出力されません。必要な引数が見つからgetoptsず、サイレントでない場合、疑問符 ('?') がnameに配置され、OPTARG設定が解除され、診断メッセージが出力されます。getoptsが無音の場合 、コロン (':') がnameに配置OPTARGされ、見つかったオプション文字に設定されます。

ご了承ください:

  1. オプション文字列の先頭のコロンはgetoptsサイレント モードになります。エラー メッセージは生成されません。

  2. 説明では、オプションのオプション引数については何も言及されていません。

私はあなたが次のような機能を求めていると仮定しています:

script -ffilename
script -f

ここで、フラグf( -f) はオプションで引数を受け入れます。bashこれはのgetoptsコマンドではサポートされていません。POSIX 関数getopt()は、その表記法をほとんどサポートしていません。実際には、コマンド ラインの最後のオプションのみが、POSIX でオプションの引数を持つことができます。

代替手段は何ですか?

部分的には、シェル スクリプトで使用getoptsbashて長いコマンド ライン オプションと短いコマンド ライン オプションを取得するを参照してください。

GNU getopt(特異な!) プログラムは、長いオプションと短いオプションをサポートし、長いオプションのオプションの引数をサポートする複雑な野獣です (そして GNU を使用します) getopt(3)。そのソースを追跡するのは面白いです。die.net のページのリンクは間違っています。ftp://ftp.kernel.org/pub/linux/utils/util-linuxの下のサブディレクトリで見つけてください( -ng. /またはそれを含むhttp://www.fsf.org/

于 2013-08-24T02:45:40.950 に答える