Bash if 문에서 정규식 일치


89

내가 여기서 뭘 잘못 했니?

공백, 소문자, 대문자 또는 숫자가 포함 된 문자열을 일치 시키려고합니다. 특수 문자도 좋지만 특정 문자를 이스케이프해야한다고 생각합니다.

TEST="THIS is a TEST title with some numbers 12345 and special char *&^%$#"

if [[ "$TEST" =~ [^a-zA-Z0-9\ ] ]]; then BLAH; fi

이것은 분명히 대문자, 소문자, 숫자 및 공백에 대해서만 테스트합니다. 그래도 작동하지 않습니다.

* 업데이트 *

좀 더 구체적 이었어 야했는데. 다음은 실제 실제 코드 줄입니다.

if [[ "$TITLE" =~ [^a-zA-Z0-9\ ] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; fi

* 업데이트 *

./anm.sh: line 265: syntax error in conditional expression
./anm.sh: line 265: syntax error near `&*#]'
./anm.sh: line 265: `  if [[ ! "$TITLE" =~ [a-zA-Z0-9 $%^\&*#] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; return; fi'

실제로 어떤 쉘을 사용하고 있습니까? / bin / sh? / bin / bash? / bin / csh?
Willem Van Onsem 2013 년

8
정규식을 변수에 넣는 것이 더 안전합니다. re='...whatever...'; [[ $string =~ $re ]](따옴표없이-이것은 그들이 없이도 작동 할 무언가를 깨뜨리는 드문 경우 중 하나입니다).
Charles Duffy 2013 년

3
대신 할당을 작은 따옴표로 묶으십시오. 큰 따옴표는 특수 문자를 제대로 보호하지 못합니다.
tripleee 2013 년

많은 thx Charles! 변수에 넣지 않는 것은 괜찮지 만, 따옴표로 묶어서는 안됩니다! 예 : [[ $var =~ .* ]]정규식 일치 .*(모든 항목). 내가 생각하는 따옴표 자체는 정규 표현식의 일부로 간주되는 따옴표 ... 사용하는 경우
스테판

4
내가 찾은 gotcha 요약 : (1.) pattern='^hello[0-9]*$'이중 사각형 표현식에서 작은 따옴표 (2.)를 사용하여 변수에 패턴을 저장하십시오. 정규식 일치가 필요한 경우 패턴을 인용하지 마십시오. 따옴표 는 정규식 패턴 일치를 비활성화하기 때문입니다. (즉, 표현식 [[ "$x" =~ $pattern ]]은 regex를 사용하여 [[ "$x" =~ "$pattern" ]]일치하고 표현식 은 정규식 일치를 비활성화하며)와 동일합니다[[ "$x" == "$pattern" ]] .
Trevor Boyd Smith

답변:


185

bash의 [[ ]]구성 에 대해 알아야 할 몇 가지 중요한 사항이 있습니다. 첫번째:

워드 분할 및 경로 확장이의 말에 수행되지 않습니다 [[]]; 물결표 확장, 매개 변수 및 변수 확장, 산술 확장, 명령 대체, 프로세스 대체 및 따옴표 제거가 수행됩니다.

두 번째 :

추가 이진 연산자 '= ~'를 사용할 수 있습니다. 연산자 오른쪽에있는 문자열은 확장 정규식으로 간주되어 그에 따라 일치됩니다 ... 패턴의 모든 부분을 인용하여 강제로 일치시킬 수 있습니다. 문자열로 .

결과적 $v으로의 양쪽 =~에서 해당 변수의 값으로 확장되지만 결과는 단어 분할 또는 경로 이름 확장이 아닙니다. 즉, 변수 확장을 왼쪽에서 인용하지 않은 채로 두는 것이 완벽하게 안전하지만 변수 확장이 오른쪽에서 발생한다는 것을 알아야합니다.

따라서 다음 [[ $x =~ [$0-9a-zA-Z] ]]과 같이 작성 $0하면 정규 표현식이 해석되기 전에 오른쪽 정규 표현식 내부가 확장되어 정규 표현식이 컴파일되지 않을 수 있습니다 ( $0ASCI 값이 다음보다 작은 숫자 또는 구두점 기호로 끝 이 확장되지 않는 한). 숫자). 당신과 같이-오른쪽을 인용하는 경우 [[ $x =~ "[$0-9a-zA-Z]" ]], 다음, 오른쪽은 일반 문자열이 아닌 정규식으로 처리됩니다 (그리고 $0여전히 확장됩니다). 이 경우에 정말로 원하는 것은[[ $x =~ [\$0-9a-zA-Z] ]]

마찬가지로 [[및 사이 ]]의 표현식은 정규식이 해석되기 전에 단어로 분할됩니다. 따라서 정규식의 공백은 이스케이프하거나 따옴표로 묶어야합니다. 문자, 숫자 또는 공백을 일치 시키려면 다음을 사용할 수 있습니다 [[ $x =~ [0-9a-zA-Z\ ] ]].. 마찬가지로 다른 문자도 이스케이프 처리해야합니다 (예 #: 인용되지 않은 경우 주석이 시작됨). 물론 패턴을 변수에 넣을 수 있습니다.

pat="[0-9a-zA-Z ]"
if [[ $x =~ $pat ]]; then ...

bash의 어휘 분석기를 통과하기 위해 이스케이프되거나 인용되어야하는 많은 문자를 포함하는 정규식의 경우 많은 사람들이이 스타일을 선호합니다. 그러나주의하십시오.이 경우 변수 확장을 인용 할 수 없습니다 .

# This doesn't work:
if [[ $x =~ "$pat" ]]; then ...

마지막으로, 당신이하려는 일은 변수에 유효한 문자 만 포함되어 있는지 확인하는 것입니다. 이 검사를 수행하는 가장 쉬운 방법은 잘못된 문자가 포함되어 있지 않은지 확인하는 것입니다. 즉, 다음과 같은 표현입니다.

valid='0-9a-zA-Z $%&#' # add almost whatever else you want to allow to the list
if [[ ! $x =~ [^$valid] ]]; then ...

!테스트를 부정하여 "일치하지 않음"연산자로 바꾸고 [^...]정규식 문자 클래스는 "이외의 모든 문자"를 의미합니다 ....

매개 변수 확장과 정규식 연산자의 조합은 bash 정규식 구문을 "거의 읽기"로 만들 수 있지만 여전히 몇 가지 문제가 있습니다. (항상 있지 않습니까?) 하나는 맨 처음을 제외하고는 인용 ]되어 $valid있어도에 넣을 수 없다는 것 $valid입니다. (그것은 Posix 정규식 규칙입니다. ]문자 클래스 에 포함 하려면 시작 부분으로 이동해야합니다. -시작 또는 끝 부분에 이동할 수 있으므로 ]및 둘 다 -필요하면로 시작 ]하고로 끝나야합니다 -. 정규식 "I know what I 'm doing"이모티콘으로 이어집니다. [][-])


7
"! ~는"일치하지 않음 "연산자" 가 사실이 아니라는 점을 지적하고 싶습니다 . 어느 사용 if ! [[ $x =~ $y ]]또는if [[ ! $x =~ $y ]]
알코올

shellchecker 동의하지 ...SC2076: Don't quote rhs of =~, it'll match literally rather than as a regex.
레오나르도

4
@leonard : "변수 확장을 인용 할 수 없습니다"라는 말과 "이것은 작동하지 않습니다"라는 주석과 어떻게 다른가요? 그것에 대해 무엇이 불분명합니까?
RICI

1
@jinbeomhong : 표현 자체는 여백을 사용하여 평소와 같이 단어로 분리됩니다. 그러나 매개 변수 및 명령 확장은 단어 분할이 아닙니다.
rici

1
@jinbeomhong : 나는 bash 매뉴얼과 다른 것을 말하는 것이 아닙니다. " 과 " 사이 의 단어 는 명령 줄이 단어로 구문 분석되는 것과 같은 방식으로 프로그램 텍스트에서 구문 분석됩니다. 그러나 명령 줄과 달리 확장 후 단어가 분할되지 않습니다. [[]]
rici

30

누군가 변수를 사용하여 예제를 원할 경우 ...

#!/bin/bash

# Only continue for 'develop' or 'release/*' branches
BRANCH_REGEX="^(develop$|release//*)"

if [[ $BRANCH =~ $BRANCH_REGEX ]];
then
    echo "BRANCH '$BRANCH' matches BRANCH_REGEX '$BRANCH_REGEX'"
else
    echo "BRANCH '$BRANCH' DOES NOT MATCH BRANCH_REGEX '$BRANCH_REGEX'"
fi

13

나는 그것을 사용하는 것을 선호 [:punct:]합니다. 또한, a-zA-Z09-9단지 수 [:alnum:]:

[[ $TEST =~ ^[[:alnum:][:blank:][:punct:]]+$ ]]

-1

또는 내가 한 것처럼 어리석은 오타를 만들고 = ~가 ~ =로 바뀌었기 때문에이 질문을 볼 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.