49

-tempBashgetoptsを使用してオプションを解析しようとしています。私は自分のスクリプトを次のように呼んでいます:

./myscript -temp /foo/bar/someFile

これが私がオプションを解析するために使用しているコードです。

while getopts "temp:shots:o:" option; do
    case $option in
        temp) TMPDIR="$OPTARG" ;;
        shots) NUMSHOTS="$OPTARG" ;;
        o) OUTFILE="$OPTARG" ;;
        *) usage ;;
    esac
done
shift $(($OPTIND - 1))

[ $# -lt 1 ] && usage
4

9 に答える 9

86

他の人が説明したように、getoptsは長いオプションを解析しません。getoptを使用することはできますが、移植性はありません(一部のプラットフォームでは壊れています...)

回避策として、シェルループを実装できます。これは、標準のgetoptsコマンドを使用する前に長いオプションを短いオプションに変換する例です(私の意見ではもっと簡単です)。

# Transform long options to short ones
for arg in "$@"; do
  shift
  case "$arg" in
    "--help") set -- "$@" "-h" ;;
    "--rest") set -- "$@" "-r" ;;
    "--ws")   set -- "$@" "-w" ;;
    *)        set -- "$@" "$arg"
  esac
done

# Default behavior
rest=false; ws=false

# Parse short options
OPTIND=1
while getopts "hrw" opt
do
  case "$opt" in
    "h") print_usage; exit 0 ;;
    "r") rest=true ;;
    "w") ws=true ;;
    "?") print_usage >&2; exit 1 ;;
  esac
done
shift $(expr $OPTIND - 1) # remove options from positional parameters
于 2015-05-04T09:23:09.843 に答える
54

getopts短いオプションのみを解析できます。

ほとんどのシステムには外部getoptコマンドもありますが、getoptは標準ではなく、すべての引数(空白と空の引数を持つ引数)を安全に処理できないため、一般に設計上壊れています。GNUgetoptのみが安全に処理できますが、 GNU固有の方法で使用してください。

より簡単な選択は、どちらも使用せず、whileループを使用してスクリプトの引数を繰り返し、自分で解析を行うことです。

例については、 http://mywiki.wooledge.org/BashFAQ/035を参照してください。

于 2012-08-19T12:01:34.240 に答える
2

getoptsシェルプロシージャが1文字のみの位置パラメータを解析するために使用します(GNUスタイルの長いオプション(--myoption)またはXF86スタイルの長いオプション(-myoption)はありません)

于 2012-08-18T22:18:09.720 に答える
1

組み込みのbashgetoptsは短いオプションのみを解析するのは事実ですが、それでも数行のスクリプトを追加して、getoptsに長いオプションを処理させることができます。

これはhttp://www.uxora.com/unix/shell-script/22-handle-long-options-with-getoptsにあるコードの一部です

  #== set options ==#
SCRIPT_OPTS=':fbF:B:-:h'
typeset -A ARRAY_OPTS
ARRAY_OPTS=(
    [foo]=f
    [bar]=b
    [foobar]=F
    [barfoo]=B
    [help]=h
    [man]=h
)

  #== parse options ==#
while getopts ${SCRIPT_OPTS} OPTION ; do
    #== translate long options to short ==#
    if [[ "x$OPTION" == "x-" ]]; then
        LONG_OPTION=$OPTARG
        LONG_OPTARG=$(echo $LONG_OPTION | grep "=" | cut -d'=' -f2)
        LONG_OPTIND=-1
        [[ "x$LONG_OPTARG" = "x" ]] && LONG_OPTIND=$OPTIND || LONG_OPTION=$(echo $OPTARG | cut -d'=' -f1)
        [[ $LONG_OPTIND -ne -1 ]] && eval LONG_OPTARG="\$$LONG_OPTIND"
        OPTION=${ARRAY_OPTS[$LONG_OPTION]}
        [[ "x$OPTION" = "x" ]] &&  OPTION="?" OPTARG="-$LONG_OPTION"

        if [[ $( echo "${SCRIPT_OPTS}" | grep -c "${OPTION}:" ) -eq 1 ]]; then
            if [[ "x${LONG_OPTARG}" = "x" ]] || [[ "${LONG_OPTARG}" = -* ]]; then 
                OPTION=":" OPTARG="-$LONG_OPTION"
            else
                OPTARG="$LONG_OPTARG";
                if [[ $LONG_OPTIND -ne -1 ]]; then
                    [[ $OPTIND -le $Optnum ]] && OPTIND=$(( $OPTIND+1 ))
                    shift $OPTIND
                    OPTIND=1
                fi
            fi
        fi
    fi

    #== options follow by another option instead of argument ==#
    if [[ "x${OPTION}" != "x:" ]] && [[ "x${OPTION}" != "x?" ]] && [[ "${OPTARG}" = -* ]]; then 
        OPTARG="$OPTION" OPTION=":"
    fi

    #== manage options ==#
    case "$OPTION" in
        f  ) foo=1 bar=0                    ;;
        b  ) foo=0 bar=1                    ;;
        B  ) barfoo=${OPTARG}               ;;
        F  ) foobar=1 && foobar_name=${OPTARG} ;;
        h ) usagefull && exit 0 ;;
        : ) echo "${SCRIPT_NAME}: -$OPTARG: option requires an argument" >&2 && usage >&2 && exit 99 ;;
        ? ) echo "${SCRIPT_NAME}: -$OPTARG: unknown option" >&2 && usage >&2 && exit 99 ;;
    esac
done
shift $((${OPTIND} - 1))

これがテストです:

# Short options test
$ ./foobar_any_getopts.sh -bF "Hello world" -B 6 file1 file2
foo=0 bar=1
barfoo=6
foobar=1 foobar_name=Hello world
files=file1 file2

# Long and short options test
$ ./foobar_any_getopts.sh --bar -F Hello --barfoo 6 file1 file2
foo=0 bar=1
barfoo=6
foobar=1 foobar_name=Hello
files=file1 file2

それ以外の場合、最近のKorn Shell ksh93では、getopts長いオプションを自然に解析し、manページを同様に表示することもできます。(http://www.uxora.com/unix/shell-script/20-getopts-with-man-page-and-long-optionsを参照してください)

ミシェルVONGVILAY。

于 2015-04-08T22:36:05.403 に答える
1

この質問は2年以上前に投稿されましたが、XFree86スタイルのロングオプションのサポートも必要であることに気付きました。また、getoptsからできることを取り入れたかったのです。GCCスイッチについて考えてみましょう-rdynamicr私は旗の手紙としてマークし、dynamic内に期待します$OPTARG...しかし、私は拒否したいのですが、に-r dynamic続く他のオプションを受け入れますr

私が以下に置いたアイデアは$OPTIND、スペース(ギャップ)が旗の後に続く場合、そうでない場合よりも1つ大きくなるという観察に基づいています。そこで、bash変数を定義して$OPTIND、と呼ばれる以前の値を保持し、ループ$PREVOPTINDの最後に更新します。がより大きい場合while、ギャップはありません(つまり)。に設定されます。代わりにがより大きい場合、ギャップ(eg )があり、設定されます。$OPTIND1$PREVOPTIND-rdynamic$GAPfalse$OPTIND2$PREVOPTIND-r dynamic$GAPtrue

usage() { echo usage: error from $1; exit -1; }

OPTIND=1
PREVOPTIND=$OPTIND
while getopts "t:s:o:" option; do
  GAP=$((OPTIND-(PREVOPTIND+1)))
  case $option in
    t) case "${OPTARG}" in
         emp)                  # i.e. -temp
           ((GAP)) && usage "-${option} and ${OPTARG}"
           TMPDIR="$OPTARG"
           ;;
         *)
           true
           ;;
       esac
       ;;
    s) case "${OPTARG}" in
         hots)                 # i.e. -shots
           ((GAP)) && usage
           NUMSHOTS="$OPTARG"
           ;;
         *) usage "-${option} and ${OPTARG}" ;;
       esac
       ;;
    o) OUTFILE="$OPTARG" ;;
    *) usage "-${option} and ${OPTARG}" ;;
  esac
  PREVOPTIND=$OPTIND
done
shift $(($OPTIND - 1))
于 2015-06-02T12:23:26.327 に答える
1

これを実現する最も簡単な方法は、getopt--longoptionsを使用することです。

これを試してみてください、これが役立つことを願っています

# Read command line options
ARGUMENT_LIST=(
    "input1"
    "input2"
    "input3"
)



# read arguments
opts=$(getopt \
    --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")" \
    --name "$(basename "$0")" \
    --options "" \
    -- "$@"
)


echo $opts

eval set --$opts

while true; do
    case "$1" in
    --input1)  
        shift
        empId=$1
        ;;
    --input2)  
        shift
        fromDate=$1
        ;;
    --input3)  
        shift
        toDate=$1
        ;;
      --)
        shift
        break
        ;;
    esac
    shift
done

これが方法です-シェルスクリプトを呼び出します

myscript.sh --input1 "ABC" --input2 "PQR" --input2 "XYZ"
于 2019-04-02T09:48:11.583 に答える
0

長いオプションに組み込みのgetoptsBashを使用することはできません。少なくとも、独自の解析関数を作成する必要がないわけではありません。代わりに/usr/ bin / getoptバイナリを確認する必要があります(私のシステムではutil-linuxパッケージによって提供されています。マイレージは異なる場合があります)。

特定の呼び出しオプションについては、getopt(1)を参照してください。

于 2012-08-18T22:17:33.620 に答える
0

@mcooliveに感謝します。

$ @のアイデアを使用して、単語全体と長いオプションを1文字のオプションに変換することができました。このアイデアを使用している人にはshift $(expr $OPTIND - 1)、getoptsループを介して引数を実行する前に含める必要があることに注意してください。

目的はまったく異なりますが、これはうまく機能しています。

# convert long word options to short word for ease of use and portability

for argu in "$@"; do
  shift
  #echo "curr arg = $1"
  case "$argu" in
"-start"|"--start")
                   # param=param because no arg is required
                   set -- "$@" "-s"
                   ;;
"-pb"|"--pb"|"-personalbrokers"|"--personalbrokers")
                   # pb +arg required
                   set -- "$@" "-p $1"; #echo "arg=$argu"
                   ;;
"-stop"|"--stop")
                   # param=param because no arg is required 
                   set -- "$@" "-S" 
                   ;;
                #  the catch all option here removes all - symbols from an
                #  argument. if an option is attempted to be passed that is
                #  invalid, getopts knows what to do...
               *)  [[ $(echo $argu | grep -E "^-") ]] && set -- "$@" "${argu//-/}" || echo "no - symbol. not touching $argu" &>/dev/null
                   ;;
esac
done

#echo -e "\n final option conversions = $@\n"
# remove options from positional parameters for getopts parsing
shift $(expr $OPTIND - 1)

declare -i runscript=0
# only p requires an argument hence the p:
 while getopts "sSp:" param; do
[[ "$param" == "p" ]] && [[ $(echo $OPTARG | grep -E "^-") ]] && funcUsage "order" 
#echo $param
#echo "OPTIND=$OPTIND"
case $param in
s)
       OPTARG=${OPTARG/ /}
       getoptsRan=1
       echo "$param was passed and this is it's arg $OPTARG"
       arg0=start
       ;;
 p)
       OPTARG=${OPTARG/ /}
       getoptsRan=1
       echo "$param was passed and this is it's arg $OPTARG"
       [[ "$OPTARG" == "all" ]] && echo -e "argument \"$OPTARG\" accepted. continuing." && (( runscript += 1 )) || usage="open"
       [[ $( echo $pbString | grep -w "$OPTARG" ) ]] && echo -e "pb $OPTARG was validated. continuing.\n" && (( runscript += 1 )) || usage="personal"
       [[ "$runscript" -lt "1" ]] && funcUsage "$usage" "$OPTARG"
       arg0=start
       ;;
S)
       OPTARG=${OPTARG/ /}
       getoptsRan=1
       echo "$param was passed and this is it's arg $OPTARG"
       arg0=stop
       ;;
*)
       getoptsRan=1
       funcUsage
       echo -e "Invalid argument\n"
       ;;
esac
done
funcBuildExcludes "$@"
shift $((OPTIND-1))
于 2017-07-06T18:04:35.430 に答える
-1

ビルトインを使用するのに問題が発生した場合の簡単なDIY getopts

使用する:

$ ./test-args.sh --a1 a1 --a2 "a 2" --a3 --a4= --a5=a5 --a6="a 6"
a1 = "a1"
a2 = "a 2"
a3 = "TRUE"
a4 = ""
a5 = "a5"
a6 = "a 6"
a7 = ""

脚本:

#!/bin/bash

function main() {
    ARGS=`getArgs "$@"`

    a1=`echo "$ARGS" | getNamedArg a1`
    a2=`echo "$ARGS" | getNamedArg a2`
    a3=`echo "$ARGS" | getNamedArg a3`
    a4=`echo "$ARGS" | getNamedArg a4`
    a5=`echo "$ARGS" | getNamedArg a5`
    a6=`echo "$ARGS" | getNamedArg a6`
    a7=`echo "$ARGS" | getNamedArg a7`

    echo "a1 = \"$a1\""
    echo "a2 = \"$a2\""
    echo "a3 = \"$a3\""
    echo "a4 = \"$a4\""
    echo "a5 = \"$a5\""
    echo "a6 = \"$a6\""
    echo "a7 = \"$a7\""

    exit 0
}


function getArgs() {
    for arg in "$@"; do
        echo "$arg"
    done
}


function getNamedArg() {
    ARG_NAME=$1

    sed --regexp-extended --quiet --expression="
        s/^--$ARG_NAME=(.*)\$/\1/p  # Get arguments in format '--arg=value': [s]ubstitute '--arg=value' by 'value', and [p]rint
        /^--$ARG_NAME\$/ {          # Get arguments in format '--arg value' ou '--arg'
            n                       # - [n]ext, because in this format, if value exists, it will be the next argument
            /^--/! p                # - If next doesn't starts with '--', it is the value of the actual argument
            /^--/ {                 # - If next do starts with '--', it is the next argument and the actual argument is a boolean one
                # Then just repla[c]ed by TRUE
                c TRUE
            }
        }
    "
}


main "$@"
于 2019-02-11T15:27:46.917 に答える