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[...]의 각 짧은 옵션 문자지름길필수 매개변수가 있음을 나타내는 콜론과 선택적 매개변수가 있음을 나타내는 두 개의 콜론이 뒤에 올 수 있습니다.

스크립트를 사용하여 원래 값을 인쇄하면 제대로 작동하는지 확인할 수 있습니다( 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해당 특정 버전이 설치되어 있는지 테스트할 수 있는 옵션이 있습니다. 다음은 제한 사항과 주의 사항에 대한 설명입니다 getopt. getopt, getopts 또는 수동 구문 분석 - 짧은 옵션과 긴 옵션을 모두 지원하려면 무엇을 사용해야 합니까?

또한 getopt이는 표준 도구가 아닙니다 getopts.

답변2

-a선택적 옵션 매개변수와 함께 옵션을 제공한다고 가정해 보겠습니다 . 옵션을 사용하면 쉘에 쉘 변수가 설정되어야 하지만, 옵션 인수가 제공되지 않으면 a_opt값으로 설정되어야 하고, 그렇지 않으면 일반적인 값으로 설정되어야 합니다.$a_default$OPTARG

매개변수 없이 사용할 시기를 결정하려면 -a다음 두 가지 경우가 있습니다.

  1. 사용자가 사용하고 있는 옵션 인수가 getopts실제로 다른 옵션 중 하나라고 생각하거나
  2. -a옵션은 목록 명령줄 끝에 사용됩니다( getopts이 경우 일반적으로 누락된 옵션에 대한 오류가 생성됩니다).

첫 번째 상황은 $OPTARG다른 옵션 중 하나와 유사한지 확인하여 처리됩니다. 그렇다면 기본값을 사용하고, 그렇지 않으면 기본값을 사용하십시오 $OPTARG. 기본값을 사용할 때 나중에 옵션 구문 분석을 다시 시작해야 합니다 -a. 이는 일부 인수( OPTIND그 중 -1개)를 제거하고 1로 재설정한 다음 위치 인수 목록 앞에 OPTIND추가하는 것을 의미합니다.$OPTARG

-a이것이 의미하는 바는 옵션 중 하나로 보이는 인수를 사용할 수 없다는 것입니다 .

두 번째 경우를 처리하는 방법은 옵션 문자열의 첫 번째 문자를 getoptsbe 로 만드는 것입니다 :. 여기에는 두 가지 효과가 있습니다.

  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"

관련 정보