"getopts"를 사용한 Bash 기능은 처음 실행 시에만 작동합니다.

"getopts"를 사용한 Bash 기능은 처음 실행 시에만 작동합니다.

f나는 다음을 기반으로 Bash에서 함수를 정의했습니다.여기 예("매개변수가 있는 옵션" 아래):

f () {
  while getopts ":a:" opt; do
    case $opt in
      a)
        echo "-a was triggered, Parameter: $OPTARG" >&2
        ;;
      \?)
        echo "Invalid option: -$OPTARG" >&2
        return 1
        ;;
      :)
        echo "Option -$OPTARG requires an argument." >&2
        return 1
        ;;
    esac
  done
}

그들은 스크립트를 사용하는 반면 저는 쉘에서 직접 함수를 정의합니다.

Bash를 처음 시작하고 다음 함수를 정의하면 모든 것이 잘 작동 f -a 123합니다 -a was triggered, Parameter: 123. 하지만 똑같은 라인을 두 번째로 실행하면,아무것도 인쇄되지 않습니다.

이 동작의 원인은 무엇입니까? Bash 3.2 및 4.3에서 발생하지만 Zsh 5.1에서는 잘 작동합니다. 이 예제는 Zsh가 아닌 Bash에 대한 것이므로 이는 놀라운 일입니다.

답변1

bash는 옵션을 얻습니다환경 변수 사용선택추적 처리를 위한 마지막 옵션 매개변수입니다. 실제로 OPTIND동일한 쉘 세션 내에서 호출될 때마다 자동으로 재설정되지 않고 getopts쉘이 호출될 때만 재설정됩니다. 따라서 getopts동일한 매개변수를 사용하여 동일한 세션에서 두 번째로 호출하면 OPTIND아무 것도 변경되지 않으며 getopts작업을 완료했다고 생각하고 아무 작업도 수행하지 않습니다.

OPTIND제대로 작동하도록 수동으로 재설정 할 수 있습니다 .

$ OPTIND=1
$ f -a 123
-a was triggered, Parameter: 123

아니면 함수를 스크립트에 넣고 스크립트를 여러 번 호출하면 됩니다.


zsh는 옵션을 얻습니다약간 다른. OPTIND일반적으로 쉘 함수가 종료될 때마다 1로 재설정됩니다.

답변2

어떤 함수에서든 지역 변수를 선언하는 것은 신성한 습관입니다. $opt, $OPTARG 및 $OPTIND를 선언하면 함수를 호출할 때마다 getopts가 실행됩니다. 함수가 완료된 후 지역 변수는 삭제됩니다.

#!/bin/bash
function some_func {
  declare opt
  declare OPTARG
  declare OPTIND

  while getopts ":a:" opt; do
    echo $opt is $OPTARG
  done
}

답변3

OPTIND=1함수 시작 부분에 설정 해야 합니다 f. 기본적으로 1이지만 인수가 구문 분석됨에 따라 증가합니다. 다시 호출 하면 getopts중단된 부분부터 계속됩니다. 두 번째 전화가 다음과 같은 경우:

f -a 123 -a 999

999를 인쇄할 때.

답변4

호출 되면 getopt변수를 통해 처리된 옵션을 추적합니다 OPTIND.

다음을 시도해 보십시오:

#!/bin/bash

f () {
    printf "Intro OPTIND: %d\n" "$OPTIND"
    while getopts ":a:b:" opt; do
        printf "Current OPTIND: %d\n" "$OPTIND"
        case $opt in
            a)
                echo "-a was triggered, Parameter: $OPTARG" >&2
                ;;
            b)
                echo "-b was triggered, Parameter: $OPTARG" >&2
                ;;
        esac
    done
    printf "Exit OPTIND: %d\n" "$OPTIND"
}

echo "Run #1"
f "$@"
echo "Run #2"
f "$@"

생산하다:

./test -a foo -b bar
Run #1
Intro OPTIND: 1
Current OPTIND: 3
-a was triggered, Parameter: foo
Current OPTIND: 5
-b was triggered, Parameter: bar
Exit OPTIND: 5
Run #2
Intro OPTIND: 5
Exit OPTIND: 5

그래서 당신은 이것을 할 수 있습니다 :

OPTIND=1

함수 시작 부분에. 또는 일반적으로 상황에 따라 더 나은 방법은 다음과 같습니다.

local OPTIND

사용하지 않으면 OPTIND함수가 구현되는 동안 while 루프가 영원히 계속됩니다. 또한 이를 사용하여 매개변수 처리를 재개할 수 있습니다. 오류가 발생한 후 또는 x 또는 y가 다른 함수를 호출하면 중단된 부분부터 다시 시작됩니다.

관련 정보