정규 표현식을 사용하여 Case 문의 숫자 일치

정규 표현식을 사용하여 Case 문의 숫자 일치

쉘 스크립트에 대한 인수가 10진수 표기법으로 정수(예: 음이 아닌 정수: 0, 1, 2, 3,…,17,…,42,… 등이지만 3.1416 또는 −5는 아님)인지 확인하고 싶습니다. (따라서 0x11 또는 0x2A와는 다릅니다). 정규식을 조건으로 사용하여 Case 문을 작성하는 방법(숫자 일치)? 나는 몇 가지 다른 접근 방식을 시도했습니다(예: [0-9]+또는 ^[0-9][0-9]*$). 그 중 어느 것도 작동하지 않습니다. 아래 예에 표시된 것처럼 유효한 숫자는 해당 숫자를 캡처하고 와일드카드와 일치시키도록 설계된 숫자 정규 표현식을 통해 전달됩니다  *.

i=1
let arg_n=$#+1

while (( $i < $arg_n )); do
    case ${!i} in
    [0-9]+)
        n=${!i}
        ;;
    *)
        echo 'Invalid argument!'
        ;;
    esac
    let i=$i+1
done

산출:

$ ./cmd.sh 64
Invalid argument!

답변1

case정규 표현식을 사용하는 대신 다음을 사용합니다.무늬

"1개 이상의 숫자"의 경우 다음을 수행합니다.

shopt -s extglob
...
    case ${!i} in
        +([[:digit:]]) )
            n=${!i}
            ;;
    ...

정규식을 사용하려면 =~다음 연산자를 사용하세요.[[...]]

if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
    n=${!i}
else
    echo "Invalid"
fi

답변2

글렌이 말했듯이, "는 case정규 표현식을 사용하지 않고 다음을 사용합니다.무늬".처럼큰 타격(1)설명하다,

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

        case명령이 먼저 확장됩니다.word, 각각의 항목과 일치시키려고 노력합니다.pattern차례로, 경로명 확장과 동일한 일치 규칙이 사용됩니다(참조:경로명 확장다음과 같은).

비슷하게,POSIX 사양설명하다,

…각무늬...확장과 비교되어야 합니다.단어, 에 설명된 규칙에 따라패턴 일치 표기법 …

그래서무늬ls -l -- *.shin 또는 와 같은 경로 이름 확장 패턴(일명 와일드카드, 일명 와일드카드)입니다 rm -- *.bak.

물론 shopt -s extglob과 는 [[ … =~ … ]] 얇게 썬 빵 이후로 가장 깔끔한 것이지만 POSIX가 아니며 원래 도구를 사용하는 방법을 아는 것이 유용할 수 있습니다. 예를 들어, 수년 동안 프로그래머는 문자열이 숫자인지 확인하여 숫자인지 여부를 확인했습니다.아니요숫자. 숫자를 (전체가) 하나 이상의 숫자로 구성된 문자열로 정의했습니다. 따라서 문자열이 비어 있거나 숫자가 아닌 문자를 포함하는 경우 문자열은 숫자가 아닙니다. case다음과 같은 문을 사용하여 이러한 조건을 테스트 할 수 있습니다 .

case "$1" in
    ("")
        # null
        ;;
    (*[!0-9]*)
        # contains non-numeric character(s)
        ;;
    (*)
        # is a whole number (non-negative integer)
esac

물론 숫자를 제외한 모든 문자를 의미하는 [!0-9]이전 쉘 표현식은 어디에 있습니까? [^0-9]( [!…]둘 다 [^…]bash에서 작동합니다.  [!…]작동하려면 POSIX가 필요하며 결과는 [^…]지정되지 않습니다.) 문자열이 어떤 종류의 비숫자인지 상관하지 않으면 비숫자 모드를 결합할 수 있습니다.

case "$1" in
    ("" | *[!0-9]*)
        # not a number
        ;;
    (*)
        # is a number
esac

연습으로서 여기에 case모든 유형의 실수(정확하게 말하면 하나 이상의 숫자로 구성된 문자열, 선택적으로 마침표( ) 및 선택적으로 .빼기 기호( ))를 처리하는 명령문이 있습니다.-

case "$1" in
    (*[!-.0-9]*)
        # contains non-numeric character(s)
        ;;
    (*?-*)
        # contains '-' somewhere other than the first position
        ;;
    (*.*.*)
        # contains multiple decimal points
        ;;
    (*)
        case "$1" in
            (*[0-9]*)
                # is a real number
                ;;
            (*)
                # not a number
        esac
esac

문자열에 실제로 최소한 하나의 숫자가 포함되어 있는지 확인하기 위해 case-within-a-를 추가했습니다 . case문자열이 비어 있는지 테스트했기 때문에 정수 예제에서는 이것이 필요하지 않았습니다. 이 명령문에서 테스트를 제거했습니다. 두 번째가 없으면 case단일 -또는 단일 .(짝수 -.)이 숫자로 간주됩니다. 물론 이러한 예외를 처리하기 위해 패턴을 추가할 수 있지만 이는 복잡해질 수 있습니다. (예를 들어, 저는 이 답변이 -.예외 중 하나라는 사실을 깨닫지 못한 채 게시할 뻔했습니다.) 저는 위의 접근 방식이 더 유연하고 강력하다고 생각합니다.

물론 숫자가 아닌 모드도 여기에서 결합할 수 있습니다 (*[!-.0-9]* | *?-* | *.*.*).

답변3

도착하다case정규 표현식을 사용하여 문의 숫자 일치, 정규식에 대한 와일드카드 지원이 있는 쉘이 필요합니다. 나는 이것으로 ksh93만을 알고 있습니다.

ksh93 glob을 사용하면 glob 모드에서 확장 정규식을 실행 ~(E)^[0-9]+$또는 사용할 수 ~(E:^[0-9]+$)있거나 Perl과 유사한 정규식을 사용할 수 있습니다(기본 정규식, 고급 정규식, SysV 정규식에서도 작동).E~(P)^\d+$GXV

그래서:

#! /bin/ksh93 -
for i do
  case $i in
    (~(E)^[0-9]+$)
      n=$i;;
    (*)
      echo >&2 'Invalid argument!'
      usage
  esac
done

관련 정보