쉘 스크립트에서 스위치를 어떻게 처리합니까?


17

인수가 아닌 스위치로 인식 -x하고 --xxxx스위치로 사용할 수있는 내장 도구가 있습니까? 아니면 모든 입력 변수를 살펴보고 대시를 테스트 한 다음 인수를 구문 분석해야합니까?

답변:


16

사용하십시오 getopts.

POSIX 사양에서와 같이 상당히 이식성이 뛰어납니다. 불행히도 긴 옵션을 지원하지 않습니다.

bash-hackers wiki와 stackoverflow 의이 질문에 대한getopts 자습서를 참조하십시오 .

짧은 옵션 만 필요한 경우 getopts(자동 오류보고 사용)의 일반적인 사용 패턴 은 다음과 같습니다.

# process arguments "$1", "$2", ... (i.e. "$@")
while getopts "ab:" opt; do
    case $opt in
    a) aflag=true ;; # Handle -a
    b) barg=$OPTARG ;; # Handle -b argument
    \?) ;; # Handle error: unknown option or missing required argument.
    esac
done

3
그 언급해야 getopt당신이 그것을 사용하기 전에 항상 GNU의 getopt에로 확인해야합니다,하지만 당신은 어쨌든로 사용해서는 안 getopts이식성 (일반적으로 좋네요) 어쨌든입니다. 당신이 경우에 어떤 이유를 호출 할 필요가하는 GNU 특정 방식으로 호출하고, 그 보장 GETOPT_COMPATIBLE환경에 있지 않습니다.
Chris Down

콜론은 무엇을 while getopts "ab:" opt합니까?
user394

1
@ user394 :옵션 문자 뒤에는 인수가 필요함을 나타냅니다. :첫 번째 문자 인 A 는 오류 메시지를 억제 함을 의미합니다.
jw013

22

bash 또는 이와 유사한 것을 사용한다고 가정합니다. 예를 들면 :

all=false
long=false

while getopts ":hal" option; do
  case $option in
    h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;;
    a) all=true ;;
    l) long=true ;;
    ?) echo "error: option -$OPTARG is not implemented"; exit ;;
  esac
done

# remove the options from the positional parameters
shift $(( OPTIND - 1 ))

ls_opts=()
$all && ls_opts+=( -a )
$long && ls_opts+=( -l )

# now, do it
ls "${ls_opts[@]}" "$@"

1
+=배열과 함께 사용 하는 경우 +1 그렇게 할 줄 몰랐어요. 좋은!
James Sneeringer

5

매개 변수를 구문 분석하려면주기를 작성해야합니다. 실제로 getopts명령을 사용 하여 쉽게 할 수 있습니다.

다음은 getopts매뉴얼 페이지 의 간단한 예입니다 .

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" "$*"

2

나는 최근에 다재다능하고 어떤 순서로든 여러 종류의 스위치를 허용하는 작업을 위해 스크립트를 작성했습니다. 나는 명백한 법적인 이유로 전체 스크립트를 공개 할 수는 없지만 (지금은 나와 함께 가지고 있지 않다는 것은 말할 것도없고) 여기에 그 고기가 있습니다. 서브 루틴에 넣고 마지막에 호출 할 수 있습니다 스크립트

options () {

    if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist
        while (( "$#" )); do  # process ALL arguments
            if [ "$1" = ^-t$ ]; then # -t short for "test"
                # do something here THEN shift the argument
                # shift removes it from $@ and reduces $# by
                # one if you supply no argument
                shift

            # we can also process multiple arguments at once
            elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments
                # do something more then remove them ALL from the arg list    
                shift 3
            else
                echo "No matching arguments!"
                echo "Usage: [script options list here]"
            fi
        done
    else
        echo "Usage: [script options list here]"
        exit 0
    fi
}

options "$@" # run options and loop through/process ALL arguments

bash 스크립트를 400 줄 / 15k 문자로 제한하는 것이 좋습니다. 앞서 언급 한 스크립트는이 크기를 넘어서서 작업하기가 매우 어려워졌습니다. 나는 Perl로 다시 작성하기 시작했는데, 이는 작업에 훨씬 더 적합합니다. bash에서 스크립트 작업을 할 때 명심하십시오. Bash는 작은 스크립트와 oneliners에 적합하지만 더 복잡한 것은 Perl로 작성하는 것이 좋습니다.

위의 테스트를 수행하지 않았으므로 작동하지 않을 수도 있지만 일반적인 아이디어를 얻을 수 있습니다.


options마지막에 전화하는 방식 이 올바르지 않으면를 반환 -bash: syntax error near unexpected token $@합니다. 로 호출하십시오 options "$@".
Chris Down

그래, 나는 Perl과 Bash를 섞었다. 수정되었습니다.
laebshade

while조건이 (($#))대신 해서는 안 됩니까?
manatwork

왜 두 개의 괄호 세트가 필요 $#합니까? 편집 : 당신이 맞아요. 수정while (( "$#" ))
laebshade
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.