이 쉘 스크립트 함수의 의미는 무엇입니까

이 쉘 스크립트 함수의 의미는 무엇입니까

누군가 나에게 예를 들어 각 줄의 의미를 말해 줄 수 있습니까? 정규 표현식이 사용되는 이유를 이해하지 못합니다.[!0122...]

#!/bin/sh
is_integer ()
{
    case "${1#[+-]}" in
        (*[!0123456789]*) return 1 ;;
        ('')              return 1 ;;
        (*)               return 0 ;;
    esac
}

답변1

#!/bin/sh

쉘 구문에 주석이 있습니다. 그러나 #!이는 파일이 실행될 때 /bin/sh해당 경로에 저장된 인터프리터를 사용하여 파일을 해석해야 하며 스크립트에 대한 경로를 인수로 사용하여 실행해야 함을 커널에 알려줍니다.

is_integer () compound-command

함수 정의를 위한 POSIX sh 구문입니다.

{
   ...
}

복합 명령~라고 불리는명령 그룹. 유일한 목적은 명령을 그룹화하여 함수의 본문으로 만드는 것입니다. 여기서는 내용이 단 하나이므로 중복됩니다.복합 명령, 그러나 { ... }명령 그룹을 각 함수의 본문으로 사용하는 것이 일반적이고 코드를 더 읽기 쉽게 만들기 때문에 일반적으로 권장됩니다. 동일한 함수를 다음과 같이 작성할 수 있습니다.

is_integer () case "${1#[+-]}" in
  (*[!0123456789]*) return 1 ;;
  ('')              return 1 ;;
  (*)               return 0 ;;
esac

case something in (pattern1 | pattern2) ...;; (pattern3)... ; esaccase/ 구조 입니다 esac(복합 명령)는 something각 패턴을 차례로 일치시키고 첫 번째 일치에서 해당 코드를 실행합니다.

이것은 .something${1#[-+]}그건매개변수 확장, 함수의 첫 번째 인수인 인수 ${param#pattern}에 연산자를 적용합니다 . 1이 연산자는 인수 내용의 시작 부분에서 패턴과 일치하는 가장 짧은 문자열을 제거합니다. 또는 문자와 일치하는 와일드카드 패턴입니다 [-+](정규 표현식 아님). 따라서 부호가 제거된 첫 번째 인수의 값으로 확장됩니다. 따라서 첫 번째 인수가 이면 2가 됩니다. 그렇다면 빈 문자열이 됩니다. 그렇다면 머물러 보세요.-+${1#[-+]}-2-22

인용되어 있음을 알 수 있습니다 "${1#[+-]}". 일반적으로 매개변수 확장을 인용해야 합니다. 그렇지 않으면 분할+글로브의 영향을 받게 됩니다. 여기서는 이런 일이 발생하지 않는 극소수 사례 중 하나이므로 엄밀히 말하면 이러한 참조는 중복됩니다(그러나 문제가 되지 않으며 여전히 좋은 습관입니다).

그런 다음 이 값은 일부 패턴과 일치됩니다.

*[!0123456789]*is *-- 임의 개수의 문자(대부분의 쉘은 비문자도 허용하지만) -- 뒤에 -- ... 또는 -- 가 아닌 [!0123456789]임의 의 문자 뒤에 임의 개수의 문자( 다시)가 옵니다. 따라서 십진수가 아닌 문자(또는 대부분의 쉘에서는 문자가 아닌 문자)를 포함하는 모든 문자열과 일치합니다.019*

일치하는 항목이 있으면 코드가 실행되어 함수가 마치 0이 아닌 숫자인 것처럼 종료 코드를 return 1반환하게 됩니다.1잘못된/실패하다.

''빈 문자열을 나타내는 방법입니다. 빈 문자열도 유효한 숫자가 아니지만 이전 패턴과 일치하지 않습니다.

그럼 *아무거나 맞춰보세요. 따라서 return 0이전 패턴과 일치하지 않는 문자열에 대해 실행됩니다. case명령문은 함수의 마지막 명령이고 case명령문은 다음을 반환하므로 여기서는 중복됩니다.성공/진짜내부에 실행 명령이 없는 경우.

따라서 여기서 함수 정의는 다음과 같이 단축될 수 있습니다.

is_integer() case ${1#[-+]} in
  ('' | *[!0123456789]*) false
esac

비록 그것이 더 명확하지는 않지만.

어쨌든 해당 코드를 사용하는 것이 맞습니다 [0123456789]. 특히 입력 유효성 검사의 경우(셸 산술 표현식에서 입력을 사용할 때 입력 유효성을 검사하는 것이 중요합니다.쉘 산술 평가에서 정리되지 않은 데이터 사용의 보안 영향) [0-9]또는 [[:digit:]]해야 합니다아니요sh특히 구현이 0에서 9 사이로 정렬된 모든 문자(또는 다중 문자 정렬 요소)와 일치 bash할 수 있고 일부 BSD에서는 0123456789 영어 시스템의 숫자뿐만 아니라 모든 십진수 시스템의 숫자와 일치할 경우 특히 사용할 수 있습니다. 영어 로케일에서.[0-9][[:digit:]]

예를 들어 GNU 시스템의 일반적인 미국 영어 로케일(현재 UTF-8을 문자 집합으로 사용하는 경향이 있음)의 in 은(는) bash일치 [0-9]합니다 .

답변2

그것은 돌아온다진짜(영) 함수에 대한 첫 번째 인수가 정수인 경우잘못된(1) 그렇지 않은 경우.

먼저 첫 번째 매개변수 값으로 시작하는 단일 또는 기호를 제거하여 +이를 수행합니다 . -그것이 바로 그 일입니다 "${1#[+-]}". 이는 ${variable#pattern}변수 값의 시작 부분에서 가장 짧은 하위 문자열 일치를 제거하는 표준 매개변수 확장을 사용합니다. 패턴은 정규식이 아니라 쉘 와일드카드 패턴이어야 합니다.patternvariable

그런 다음 일련의 패턴 일치(정규식이 아닌 와일드카드 패턴)를 통해 결과 값을 실행합니다. 첫 번째로 일치하는 패턴이 해당 문을 트리거합니다 return.

첫 번째 패턴은 문자열에 숫자 이외의 문자가 있는지 테스트합니다. 이 패턴은 *[!0-9]*or로 쓸 수도 있습니다 *[![:digit:]]*(그러나 다음도 참조하세요).여기). 이 함수는 정규식 문자 클래스 또는 범위에서 a와 동일한 방식으로 수행됩니다 !(즉, 에 표시된 대로 일부 쉘에서는 여기에서도 a를 허용합니다). 즉, 주어진 문자 클래스 또는 범위를 반대로 바꿉니다. 이 패턴은 "주어진 문자열의 어느 위치에서든 숫자가 아닌 것과 일치"하는 것으로 이해될 수 있습니다. 쉘 글로빙 패턴은 항상 고정되어 있으므로 패턴의 시작과 끝 부분에 필요합니다(해당 정규식은 , 또는 이며 명시적 고정은 필요하지 않음).^[^...]^*[!0123456789]**[^0-9]^.*[^0-9].*$

두 번째 모드는 문자열이 비어 있는지 테스트합니다.

마지막 패턴은 모든 문자열과 일치합니다.

in 함수의 대체 구현 bash( ==inside와의 패턴 일치 허용 [[ ... ]]):

is_integer () {
    set -- "${1#[+-]}"

    if [ -z "$1" ] || [[ $1 == *[!0-9]* ]]; then
        return 1
    fi

    return 0
}

관련 정보