누군가 나에게 예를 들어 각 줄의 의미를 말해 줄 수 있습니까? 정규 표현식이 사용되는 이유를 이해하지 못합니다.[!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)... ; esac
case
/ 구조 입니다 esac
(복합 명령)는 something
각 패턴을 차례로 일치시키고 첫 번째 일치에서 해당 코드를 실행합니다.
이것은 .something
${1#[-+]}
그건매개변수 확장, 함수의 첫 번째 인수인 인수 ${param#pattern}
에 연산자를 적용합니다 . 1
이 연산자는 인수 내용의 시작 부분에서 패턴과 일치하는 가장 짧은 문자열을 제거합니다. 또는 문자와 일치하는 와일드카드 패턴입니다 [-+]
(정규 표현식 아님). 따라서 부호가 제거된 첫 번째 인수의 값으로 확장됩니다. 따라서 첫 번째 인수가 이면 2가 됩니다. 그렇다면 빈 문자열이 됩니다. 그렇다면 머물러 보세요.-
+
${1#[-+]}
-2
-
2
2
인용되어 있음을 알 수 있습니다 "${1#[+-]}"
. 일반적으로 매개변수 확장을 인용해야 합니다. 그렇지 않으면 분할+글로브의 영향을 받게 됩니다. 여기서는 이런 일이 발생하지 않는 극소수 사례 중 하나이므로 엄밀히 말하면 이러한 참조는 중복됩니다(그러나 문제가 되지 않으며 여전히 좋은 습관입니다).
그런 다음 이 값은 일부 패턴과 일치됩니다.
*[!0123456789]*
is *
-- 임의 개수의 문자(대부분의 쉘은 비문자도 허용하지만) -- 뒤에 -- ... 또는 -- 가 아닌 [!0123456789]
임의 의 문자 뒤에 임의 개수의 문자( 다시)가 옵니다. 따라서 십진수가 아닌 문자(또는 대부분의 쉘에서는 문자가 아닌 문자)를 포함하는 모든 문자열과 일치합니다.0
1
9
*
일치하는 항목이 있으면 코드가 실행되어 함수가 마치 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}
변수 값의 시작 부분에서 가장 짧은 하위 문자열 일치를 제거하는 표준 매개변수 확장을 사용합니다. 패턴은 정규식이 아니라 쉘 와일드카드 패턴이어야 합니다.pattern
variable
그런 다음 일련의 패턴 일치(정규식이 아닌 와일드카드 패턴)를 통해 결과 값을 실행합니다. 첫 번째로 일치하는 패턴이 해당 문을 트리거합니다 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
}