bash에서 getopts를 사용하는 방법의 예


345

myscript이런 식으로 파일 을 호출하고 싶습니다 .

$ ./myscript -s 45 -p any_string

또는

$ ./myscript -h  #should display help
$ ./myscript     #should display help

내 요구 사항은 다음과 같습니다

  • getopt 입력 인수를 얻으려면 여기
  • -s오류를 반환하지 않으면 존재 하는지 확인하십시오.
  • 이후의 값 -s이 45 또는 90인지 확인하십시오.
  • -p존재하고 다음에 입력 문자열이 있는지 확인하십시오.
  • 사용자가 입력 ./myscript -h하거나 ./myscript도움말을 표시하면

나는 지금 까지이 코드를 시도했다 :

#!/bin/bash
while getopts "h:s:" arg; do
  case $arg in
    h)
      echo "usage" 
      ;;
    s)
      strength=$OPTARG
      echo $strength
      ;;
  esac
done

그러나 그 코드를 사용하면 오류가 발생합니다. Bash와 getopt어떻게합니까?


2
옵션은 선택 사항입니다. 로 지정된 값이 필요한 경우 -s위치 인수로 지정하십시오 ./myscript 45 anystring.
chepner 2016 년

@chepner$./myscript -s 45 -p any_string
MOHAMED

-p실제로 옵션 이라면 괜찮습니다 (즉, 프로그램이 없으면 프로그램을 진행할 수 있습니다). 이 경우, ./myscript 45 -p any_string. (나는 생각 getopt(가) 반면, 혼합 옵션 및 위치 인수를 처리 할 수있는 bash내장 명령 getopts옵션 다음에 위치하는 모든 위치 인수가 필요합니다.)
chepner

답변:


513
#!/bin/bash

usage() { echo "Usage: $0 [-s <45|90>] [-p <string>]" 1>&2; exit 1; }

while getopts ":s:p:" o; do
    case "${o}" in
        s)
            s=${OPTARG}
            ((s == 45 || s == 90)) || usage
            ;;
        p)
            p=${OPTARG}
            ;;
        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

if [ -z "${s}" ] || [ -z "${p}" ]; then
    usage
fi

echo "s = ${s}"
echo "p = ${p}"

예제 실행 :

$ ./myscript.sh
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -h
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s "" -p ""
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 10 -p foo
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 45 -p foo
s = 45
p = foo

$ ./myscript.sh -s 90 -p bar
s = 90
p = bar

19
getopts 호출에서 왜 주요 콜론이 있습니까? "h"뒤에 콜론이 있습니까?
e40

7
usage()정말로 1을 반환 해야합니까 ?
Pithikos

6
@Pithikos 좋은 지적. 상식은 -h그것을 통해 호출 할 때 return 0, 존재하지 않는 플래그를 칠 때 반환해야 한다는 것을 알려줍니다 >0(단순성을 위해 나는이 경우를 구별하지 않았으며 후자의 경우 사용법 텍스트를 인쇄하도록 강요하지 않습니다) . != 0그래도 항상 돌아 오는 프로그램을 보았습니다 -h/--help. 사람들이 이것을 상용구로 사용하는 경우 스 니펫을 업데이트해야합니까?
Adrian Frühwirth

1
@ A.Danischewski 이것은 ( getopts') 디자인에 의한 것으로, "선택적 인수"와 같은 것은 없습니다 getopts. 구문 분석기는 다음 토큰이 현재 옵션 또는 옵션 자체에 대한 인수인지 여부를 -p의도 한 값일 수 있으므로 알 수 없습니다. 당신은 할 수 있습니다 당신이 절대적으로 옵션 매개 변수가 다른 유효한 옵션, 예처럼 보일 수 없음을 알고있는 경우이 주위를 해킹, 그러나 사람은 선택적 인수가 POSIX에서 정의되지 않은 이유가 말할 수 있습니다.
Adrian Frühwirth

4
@ user1011471 맞습니다! 말하자면 중괄호는 bash변수를 식별 할 때 어휘 분석기를 돕는다 . 그들은 많은 경우에 불필요하며 항상 사용한다는 사실은 개인 코딩 스타일의 문제입니다. 나에게는 모호성과 관련하여 구문 분석 규칙을 기억하는 대신 항상 사용하는 것이 더 쉽고 더 예쁘다. C 스타일 언어 (미학 및 / 또는 어리석은 실수를 피하는 것) if (foo) { bar; }대신에 쓰는 이유와 거의 같습니다 if (foo) bar;.
Adrian Frühwirth

109

원래 코드의 문제점은 다음과 같습니다.

  • h:해서는 안되는 곳에 매개 변수를 기대하므로 h(콜론없이) 그냥 변경하십시오
  • 기대 하려면 인수 목록에 -p any_string추가해야 p:합니다

기본적으로 :옵션 뒤에는 인수가 필요하다는 의미입니다.


기본 구문 getopts은 다음과 같습니다 (참조 man bash) :

getopts OPTSTRING VARNAME [ARGS...]

어디:

  • OPTSTRING 예상 인수 목록이있는 문자열입니다.

    • h- 매개 변수가 -h 없는 옵션 확인하십시오 . 지원되지 않는 옵션에 오류가 있습니다.
    • h:- 매개 변수 가있는 옵션 -h 확인하십시오 . 지원되지 않는 옵션에 오류가 있습니다.
    • abc- 옵션에 대한 검사 -a, -b, -c, 제공 되지 않는 옵션에 대한 오류;
    • :abc- 옵션에 대한 검사 -a, -b, -c, 침묵 지원되지 않는 옵션에 대한 오류;

      즉, 옵션 앞의 콜론을 사용하면 코드의 오류를 처리 할 수 ​​있습니다. ?지원되지 않는 옵션 인 :경우 값이 누락 된 경우 변수에 포함 됩니다 .

  • OPTARG -현재 인수 값으로 설정

  • OPTERR -Bash가 오류 메시지를 표시해야하는지 여부를 나타냅니다.

따라서 코드는 다음과 같습니다.

#!/usr/bin/env bash
usage() { echo "$0 usage:" && grep " .)\ #" $0; exit 0; }
[ $# -eq 0 ] && usage
while getopts ":hs:p:" arg; do
  case $arg in
    p) # Specify p value.
      echo "p is ${OPTARG}"
      ;;
    s) # Specify strength, either 45 or 90.
      strength=${OPTARG}
      [ $strength -eq 45 -o $strength -eq 90 ] \
        && echo "Strength is $strength." \
        || echo "Strength needs to be either 45 or 90, $strength found instead."
      ;;
    h | *) # Display help.
      usage
      exit 0
      ;;
  esac
done

사용법 예 :

$ ./foo.sh 
./foo.sh usage:
    p) # Specify p value.
    s) # Specify strength, either 45 or 90.
    h | *) # Display help.
$ ./foo.sh -s 123 -p any_string
Strength needs to be either 45 or 90, 123 found instead.
p is any_string
$ ./foo.sh -s 90 -p any_string
Strength is 90.
p is any_string

참조 : Bash Hackers Wiki의 소규모 getopts 자습서


2
사용법 기능을 다음과 같이 변경하십시오 usage() { echo "$0 usage:" && grep "[[:space:]].)\ #" $0 | sed 's/#//' | sed -r 's/([a-z])\)/-\1/'; exit 0; }. 문자 옵션 앞에 하나의 공백 문자 만 설명하고 주석에서 #을 제거하고 문자 옵션 앞에 '-'를 추가하여 명령을 더 명확하게 만듭니다.
poagester

2
@kenorb : 옵션 앞의 콜론은 지원되지 않는 옵션을 무시하지 않지만 bash의 오류를 침묵시키고 코드에서 처리 할 수 ​​있습니다. 변수는 '?'를 포함합니다 지원되지 않는 옵션의 경우 값이 누락 된 경우 ':'.
Hynek -Pichi- Vychodil 2012

1
자세한 문서에 감사드립니다 :.이 노트를 볼 때까지 제대로 얻을 수 없었습니다 . :인수가 예상되는 옵션 에 a를 추가해야합니다 .
Aukhan

51

사용하다 getopt

왜 getopt?

혼동을 피하기 위해 정교한 명령 행 인수를 구문 분석하고 구문 분석중인 옵션을 명확하게하여 명령을 읽는 사람이 현재 상황을 이해할 수 있도록합니다.

getopt 란 무엇입니까?

getopt쉘 프로 시저로 쉽게 구문 분석하고 법적 옵션을 확인하기 위해 명령 행에서 옵션을 분류 (구문 분석)하는 데 사용됩니다. 이를 위해 GNU getopt(3)루틴을 사용합니다 .

getopt 다음과 같은 유형의 옵션을 가질 수 있습니다.

  1. 무가치 옵션
  2. 키-값 쌍 옵션

참고 :이 문서에서 구문을 설명하는 동안 :

  • [] 안에있는 것은 구문 / 예시의 선택적 매개 변수입니다.
  • 자리 표시 자이므로 실제 값으로 대체해야합니다.

사용하는 방법 getopt?

구문 : 첫 번째 양식

getopt optstring parameters

예 :

# This is correct
getopt "hv:t::" "-v 123 -t123"  
getopt "hv:t::" "-v123 -t123"  # -v and 123 doesn't have whitespace

# -h takes no value.
getopt "hv:t::" "-h -v123"


# This is wrong. after -t can't have whitespace.
# Only optional params cannot have whitespace between key and value
getopt "hv:t::" "-v 123 -t 123"

# Multiple arguments that takes value.
getopt "h:v:t::g::" "-h abc -v 123 -t21"

# Multiple arguments without value
# All of these are correct
getopt "hvt" "-htv"
getopt "hvt" "-h -t -v"
getopt "hvt" "-tv -h"

여기서 h, v, t는 옵션이고 -h -v -t는 명령 줄에서 옵션을 제공하는 방법입니다.

  1. 'h'는 값이없는 옵션입니다.
  2. 'v :'는 옵션 -v에 값이 있으며 필수 옵션임을 의미합니다. ':'은 값이 있음을 의미합니다.
  3. 't ::'는 옵션 -t에 값이 있지만 선택 사항임을 나타냅니다. '::'은 선택 사항을 의미합니다.

선택적 param에서 value는 옵션으로 공백을 구분할 수 없습니다. 따라서 "-t123"예에서 -t는 옵션 123이 값입니다.

구문 : 두 번째 양식

getopt [getopt_options] [--] [optstring] [parameters]

여기서 getopt가 다섯 부분으로 분할 된 후

  • 명령 자체, 즉 getopt
  • getopt_options는 인수를 구문 분석하는 방법을 설명합니다. 단일 대시 길이 옵션, 이중 대시 옵션.
  • -, 구문 분석하려는 옵션과 허용되는 짧은 옵션에서 getopt_options를 분리합니다.
  • 짧은 옵션은-가 발견 된 직후에 사용됩니다. 양식 첫 구문과 같습니다.
  • 매개 변수는 프로그램에 전달한 옵션입니다. 구문 분석하고 실제 값을 설정하려는 옵션.

getopt -l "name:,version::,verbose" -- "n:v::V" "--name=Karthik -version=5.2 -verbose"

구문 : 세 번째 양식

getopt [getopt_options] [-o options] [--] [optstring] [parameters]

여기서 getopt가 다섯 부분으로 분할 된 후

  • 명령 자체, 즉 getopt
  • getopt_options는 인수를 구문 분석하는 방법을 설명합니다. 단일 대시 길이 옵션, 이중 대시 옵션.
  • 짧은 옵션, 즉 -o 또는 --options. 양식의 첫 번째 구문과 동일하지만 옵션 "-o"및 "-"(이중 대시) 앞에
  • -, 구문 분석하려는 옵션과 허용되는 짧은 옵션에서 getopt_options를 분리합니다.
  • 매개 변수는 프로그램에 전달한 옵션입니다. 구문 분석하고 실제 값을 설정하려는 옵션.

getopt -l "name:,version::,verbose" -a -o "n:v::V" -- "-name=Karthik -version=5.2 -verbose"

GETOPT_OPTIONS

getopt_options는 명령 행 매개 변수의 구문 분석 방법을 변경합니다.

다음은 getopt_options 중 일부입니다

옵션 : -l 또는 --longoptions

getopt 명령은 다중 문자 옵션을 인식 할 수 있어야 함을 의미합니다. 여러 옵션은 쉼표로 구분됩니다.

예를 들어, --name=Karthik명령 행에서 전송 된 긴 옵션입니다. getopt에서 긴 옵션의 사용법은

getopt "name:,version" "--name=Karthik"

name :이 지정되었으므로 옵션에 값이 포함되어야합니다

옵션 : -a 또는 --alternative

getopt 명령은 long 옵션에 이중 대시 '-'가 아닌 단일 대시 '-'가 있어야 함을 의미합니다.

예, 대신에게 --name=Karthik당신은 사용할 수 있습니다-name=Karthik

getopt "name:,version" "-name=Karthik"

코드가 포함 된 완전한 스크립트 예제 :

#!/bin/bash

# filename: commandLine.sh
# author: @theBuzzyCoder

showHelp() {
# `cat << EOF` This means that cat should stop reading when EOF is detected
cat << EOF  
Usage: ./installer -v <espo-version> [-hrV]
Install Pre-requisites for EspoCRM with docker in Development mode

-h, -help,          --help                  Display help

-v, -espo-version,  --espo-version          Set and Download specific version of EspoCRM

-r, -rebuild,       --rebuild               Rebuild php vendor directory using composer and compiled css using grunt

-V, -verbose,       --verbose               Run script in verbose mode. Will print out each step of execution.

EOF
# EOF is found above and hence cat command stops reading. This is equivalent to echo but much neater when printing out.
}


export version=0
export verbose=0
export rebuilt=0

# $@ is all command line parameters passed to the script.
# -o is for short options like -v
# -l is for long options with double dash like --version
# the comma separates different long options
# -a is for long options with single dash like -version
options=$(getopt -l "help,version:,verbose,rebuild,dryrun" -o "hv:Vrd" -a -- "$@")

# set --:
# If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters 
# are set to the arguments, even if some of them begin with a ‘-’.
eval set -- "$options"

while true
do
case $1 in
-h|--help) 
    showHelp
    exit 0
    ;;
-v|--version) 
    shift
    export version=$1
    ;;
-V|--verbose)
    export verbose=1
    set -xv  # Set xtrace and verbose mode.
    ;;
-r|--rebuild)
    export rebuild=1
    ;;
--)
    shift
    break;;
esac
shift
done

이 스크립트 파일을 실행 :

# With short options grouped together and long option
# With double dash '--version'

bash commandLine.sh --version=1.0 -rV
# With short options grouped together and long option
# With single dash '-version'

bash commandLine.sh -version=1.0 -rV

# OR with short option that takes value, value separated by whitespace
# by key

bash commandLine.sh -v 1.0 -rV

# OR with short option that takes value, value without whitespace
# separation from key.

bash commandLine.sh -v1.0 -rV

# OR Separating individual short options

bash commandLine.sh -v1.0 -r -V


getopt vs getopts .. 매우 다른 크로스 플랫폼 준수
shadowbq

35

getopt(내 배포판에 포함 /usr/share/getopt/getopt-parse.bash) 패키지 된 예제 는 모든 경우를 다루는 것처럼 보입니다.

#!/bin/bash

# A small example program for using the new getopt(1) program.
# This program will only work with bash(1)
# An similar program using the tcsh(1) script language can be found
# as parse.tcsh

# Example input and output (from the bash prompt):
# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "
# Option a
# Option c, no argument
# Option c, argument `more'
# Option b, argument ` very long '
# Remaining arguments:
# --> `par1'
# --> `another arg'
# --> `wow!*\?'

# Note that we use `"$@"' to let each command-line parameter expand to a 
# separate word. The quotes around `$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
     -n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
    case "$1" in
        -a|--a-long) echo "Option a" ; shift ;;
        -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
        -c|--c-long) 
            # c has an optional argument. As we are in quoted mode,
            # an empty parameter will be generated if its optional
            # argument is not found.
            case "$2" in
                "") echo "Option c, no argument"; shift 2 ;;
                *)  echo "Option c, argument \`$2'" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done
echo "Remaining arguments:"
for arg do echo '--> '"\`$arg'" ; done

11
당신이하지 않으면 외부 명령 getopt는 (1), 사용하는 것이 결코 안전 을 알고 는 GNU의 getopt는, 당신은 GNU 특정 방식으로 호출, 그리고 당신은 GETOPT_COMPATIBLE 환경에 있지 않은지 확인합니다. 대신 getopts (쉘 내장)를 사용하거나 단순히 위치 매개 변수를 반복하십시오.
Gilles Quenot

@sputnick, tyvm은 이것을 몰랐습니다.
브라이언 케인

14
예, 해당 표준에서 사용하기에 안전한 외부 명령은 없습니다. 내장 된 getopts에는 중요한 기능이 누락되어 있으며 getopt 기능을 이식하는 것보다 쉬운 GETOPT_COMPATIBLE을 확인하려는 경우.
마이클 테리

12

나는 이것이 이미 답변되어 있음을 알고 있지만, 기록과 나와 같은 요청을 가진 사람을 위해이 관련 답변을 게시하기로 결정했습니다. 코드는 코드를 설명하는 주석으로 가득 차 있습니다.

업데이트 된 답변 :

파일을 getopt.sh다음 과 같이 저장하십시오 .

#!/bin/bash

function get_variable_name_for_option {
    local OPT_DESC=${1}
    local OPTION=${2}
    local VAR=$(echo ${OPT_DESC} | sed -e "s/.*\[\?-${OPTION} \([A-Z_]\+\).*/\1/g" -e "s/.*\[\?-\(${OPTION}\).*/\1FLAG/g")

    if [[ "${VAR}" == "${1}" ]]; then
        echo ""
    else
        echo ${VAR}
    fi
}

function parse_options {
    local OPT_DESC=${1}
    local INPUT=$(get_input_for_getopts "${OPT_DESC}")

    shift
    while getopts ${INPUT} OPTION ${@};
    do
        [ ${OPTION} == "?" ] && usage
        VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
            [ "${VARNAME}" != "" ] && eval "${VARNAME}=${OPTARG:-true}" # && printf "\t%s\n" "* Declaring ${VARNAME}=${!VARNAME} -- OPTIONS='$OPTION'"
    done

    check_for_required "${OPT_DESC}"

}

function check_for_required {
    local OPT_DESC=${1}
    local REQUIRED=$(get_required "${OPT_DESC}" | sed -e "s/\://g")
    while test -n "${REQUIRED}"; do
        OPTION=${REQUIRED:0:1}
        VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
                [ -z "${!VARNAME}" ] && printf "ERROR: %s\n" "Option -${OPTION} must been set." && usage
        REQUIRED=${REQUIRED:1}
    done
}

function get_input_for_getopts {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"
}

function get_optional {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/[^[]*\(\[[^]]*\]\)[^[]*/\1/g" -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"
}

function get_required {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/\[[^[]*\]//g" -e "s/[][ -]//g"
}

function usage {
    printf "Usage:\n\t%s\n" "${0} ${OPT_DESC}"
    exit 10
}

그런 다음 다음과 같이 사용할 수 있습니다.

#!/bin/bash
#
# [ and ] defines optional arguments
#

# location to getopts.sh file
source ./getopt.sh
USAGE="-u USER -d DATABASE -p PASS -s SID [ -a START_DATE_TIME ]"
parse_options "${USAGE}" ${@}

echo ${USER}
echo ${START_DATE_TIME}

오래된 답변 :

최근에 일반적인 접근 방식을 사용해야했습니다. 이 솔루션을 발견했습니다.

#!/bin/bash
# Option Description:
# -------------------
#
# Option description is based on getopts bash builtin. The description adds a variable name feature to be used
# on future checks for required or optional values.
# The option description adds "=>VARIABLE_NAME" string. Variable name should be UPPERCASE. Valid characters
# are [A-Z_]*.
#
# A option description example:
#   OPT_DESC="a:=>A_VARIABLE|b:=>B_VARIABLE|c=>C_VARIABLE"
#
# -a option will require a value (the colon means that) and should be saved in variable A_VARIABLE.
# "|" is used to separate options description.
# -b option rule applies the same as -a.
# -c option doesn't require a value (the colon absense means that) and its existence should be set in C_VARIABLE
#
#   ~$ echo get_options ${OPT_DESC}
#   a:b:c
#   ~$
#


# Required options 
REQUIRED_DESC="a:=>REQ_A_VAR_VALUE|B:=>REQ_B_VAR_VALUE|c=>REQ_C_VAR_FLAG"

# Optional options (duh)
OPTIONAL_DESC="P:=>OPT_P_VAR_VALUE|r=>OPT_R_VAR_FLAG"

function usage {
    IFS="|"
    printf "%s" ${0}
    for i in ${REQUIRED_DESC};
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
    printf " %s" "-${i:0:1} $VARNAME"
    done

    for i in ${OPTIONAL_DESC};
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
        printf " %s" "[-${i:0:1} $VARNAME]"
    done
    printf "\n"
    unset IFS
    exit
}

# Auxiliary function that returns options characters to be passed
# into 'getopts' from a option description.
# Arguments:
#   $1: The options description (SEE TOP)
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   OPTIONS=$(get_options ${OPT_DESC})
#   echo "${OPTIONS}"
#
# Output:
#   "h:f:PW"
function get_options {
    echo ${1} | sed -e "s/\([a-zA-Z]\:\?\)=>[A-Z_]*|\?/\1/g"
}

# Auxiliary function that returns all variable names separated by '|'
# Arguments:
#       $1: The options description (SEE TOP)
#
# Example:
#       OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#       VARNAMES=$(get_values ${OPT_DESC})
#       echo "${VARNAMES}"
#
# Output:
#       "H_VAR|F_VAR|P_VAR|W_VAR"
function get_variables {
    echo ${1} | sed -e "s/[a-zA-Z]\:\?=>\([^|]*\)/\1/g"
}

# Auxiliary function that returns the variable name based on the
# option passed by.
# Arguments:
#   $1: The options description (SEE TOP)
#   $2: The option which the variable name wants to be retrieved
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   H_VAR=$(get_variable_name ${OPT_DESC} "h")
#   echo "${H_VAR}"
#
# Output:
#   "H_VAR"
function get_variable_name {
    VAR=$(echo ${1} | sed -e "s/.*${2}\:\?=>\([^|]*\).*/\1/g")
    if [[ ${VAR} == ${1} ]]; then
        echo ""
    else
        echo ${VAR}
    fi
}

# Gets the required options from the required description
REQUIRED=$(get_options ${REQUIRED_DESC})

# Gets the optional options (duh) from the optional description
OPTIONAL=$(get_options ${OPTIONAL_DESC})

# or... $(get_options "${OPTIONAL_DESC}|${REQUIRED_DESC}")

# The colon at starts instructs getopts to remain silent
while getopts ":${REQUIRED}${OPTIONAL}" OPTION
do
    [[ ${OPTION} == ":" ]] && usage
    VAR=$(get_variable_name "${REQUIRED_DESC}|${OPTIONAL_DESC}" ${OPTION})
    [[ -n ${VAR} ]] && eval "$VAR=${OPTARG}"
done

shift $(($OPTIND - 1))

# Checks for required options. Report an error and exits if
# required options are missing.

# Using function version ...
VARS=$(get_variables ${REQUIRED_DESC})
IFS="|"
for VARNAME in $VARS;
do
    [[ -v ${VARNAME} ]] || usage
done
unset IFS

# ... or using IFS Version (no function)
OLDIFS=${IFS}
IFS="|"
for i in ${REQUIRED_DESC};
do
    VARNAME=$(echo $i | sed -e "s/.*=>//g")
    [[ -v ${VARNAME} ]] || usage
    printf "%s %s %s\n" "-${i:0:1}" "${!VARNAME:=present}" "${VARNAME}"
done
IFS=${OLDIFS}

나는 이것을 대략 테스트하지 않았으므로 거기에 몇 가지 버그가있을 수 있습니다.


1
getopts함수에서 사용 하는 경우 함수에 추가 local OPTIND OPTARG하십시오
glenn jackman

@glennjackman은 실제로 사용하는 것보다 sed 방식과 비슷합니다getopts
Sebastian

8

POSIX 7 예

표준에서 예제를 확인하는 것도 좋습니다. http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)   printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"

그런 다음 시도해 볼 수 있습니다.

$ sh a.sh
Remaining arguments are: 
$ sh a.sh -a
Option -a specified
Remaining arguments are: 
$ sh a.sh -b
No arg for -b option
Usage: a.sh: [-a] [-b value] args
$ sh a.sh -b myval
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh -a -b myval
Option -a specified
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh remain
Remaining arguments are: remain
$ sh a.sh -- -a remain
Remaining arguments are: -a remain

우분투 17.10에서 테스트되었으며 sh대시 0.5.8입니다.


0

"getops"와 "getopt"는 매우 제한적입니다. "getopt"는 전혀 사용하지 않는 것이 좋지만 긴 옵션을 제공합니다. "getopts"는 "-a" "-b"와 같은 단일 문자 옵션 만 허용합니다. 둘 중 하나를 사용할 때 몇 가지 단점이 더 있습니다.

"getopts"와 "getopt"를 대체하는 작은 스크립트를 작성했습니다. 시작일 것입니다. 아마 많이 향상되었을 것입니다.

08-04-2020 업데이트 : "--package-name"과 같은 하이픈 지원이 추가되었습니다.

사용법 : "./script.sh package install --package"space with name "--build --archive"

# Example:
# parseArguments "${@}"
# echo "${ARG_0}" -> package
# echo "${ARG_1}" -> install
# echo "${ARG_PACKAGE}" -> "name with space"
# echo "${ARG_BUILD}" -> 1 (true)
# echo "${ARG_ARCHIVE}" -> 1 (true)
function parseArguments() {
  PREVIOUS_ITEM=''
  COUNT=0
  for CURRENT_ITEM in "${@}"
  do
    if [[ ${CURRENT_ITEM} == "--"* ]]; then
      printf -v "ARG_$(formatArgument "${CURRENT_ITEM}")" "%s" "1" # could set this to empty string and check with [ -z "${ARG_ITEM-x}" ] if it's set, but empty.
    else
      if [[ $PREVIOUS_ITEM == "--"* ]]; then
        printf -v "ARG_$(formatArgument "${PREVIOUS_ITEM}")" "%s" "${CURRENT_ITEM}"
      else
        printf -v "ARG_${COUNT}" "%s" "${CURRENT_ITEM}"
      fi
    fi

    PREVIOUS_ITEM="${CURRENT_ITEM}"
    (( COUNT++ ))
  done
}

# Format argument.
function formatArgument() {
  ARGUMENT="${1^^}" # Capitalize.
  ARGUMENT="${ARGUMENT/--/}" # Remove "--".
  ARGUMENT="${ARGUMENT//-/_}" # Replace "-" with "_".
  echo "${ARGUMENT}"
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.