쉘은 여러 줄 문자열의 마지막 줄에 지정된 패턴이 포함되어 있는지 테스트합니다.

쉘은 여러 줄 문자열의 마지막 줄에 지정된 패턴이 포함되어 있는지 테스트합니다.

여러 줄 문자열이 지정된 패턴을 포함하는 줄로 끝나는지 확인하고 싶습니다.

이 코드는 실패하고 일치하지 않습니다.

s=`echo hello && echo world && echo OK`
[[ "$s" =~ 'OK$' ]] && echo match

답변1

bash3.2 이상 에서 3.1과의 호환성이 활성화되지 않은 경우( compat31또는 옵션 사용 BASH_COMPAT=3.1) 인용된 정규식 연산자( 인용된 연산자( , , , ) \와 함께 사용되지 않음 )는 특별한 의미가 제거됩니다.bash'...'"..."$'...'$"..."

[[ $var =~ 'OK$' ]]

OK$리터럴을 포함하는 문자열 만 일치 ( $리터럴 일치 $)

[[ $var =~ OK$ ]]

다음으로 끝나는 문자열과 일치합니다 OK(즉, $RE 연산자는 문자열 끝에서 일치합니다).

이는 정규식이나 변수에 저장된 특정 대체 결과에도 적용됩니다.

[[ $var =~ $regexp ]]   # $var matches $regexp
[[ $var =~ "$string" ]] # $var contains $string

쉘 구문에 대해 일부 문자(예: 일치하지 않는 경우 공백,,,, 괄호)를 인용해야 하기 때문에 이것이 어색해질 수 있습니다 <. 예를 들어, 정규식(3자 뒤에 a, a 또는 a가 오는)을 일치시키려면 다음과 같은 것이 필요합니다.>&.{3} <> [)}]&" <> ")}&

[[ $var =~ .{3}" <> "[}\)]\& ]]

어떤 문자를 인용해야 할지 확실하지 않은 경우,언제든지 임시 변수를 사용할 수 있습니다.. 이는 또한 코드를 호환 가능하게 만들 거나 다음을 의미 합니다 bash31.zshksh93

pattern='.{3} <> [})]&'
[[ $var =~ $pattern ]] # remember *not* to quote $pattern here

compat31이는 (or) 옵션을 사용하지 않고 시스템 정규 표현식의 POSIX 이외의 확장 연산자를 활용할 수 있는 유일한 방법이기도 합니다.BASH_COMPAT=3.1

예를 들어, \<많은 정규식 엔진에서 이를 단어 경계로 처리하려면 다음이 필요합니다.

pattern='\<word\>'
[[ $var =~ $pattern ]]

행위:

[[ $var =~ \<word\> ]]

이를 쉘 인용 연산자로 bash취급 하고 정규식 라이브러리에 전달하기 전에 제거하는 것처럼 작동하지 않습니다 .\<word>

ksh93의 경우 상황이 훨씬 더 나쁩니다.

[[ $var =~ "x.*$" ]]

예를 들어 에서는 일치 whatever-xa*하지만 일치하지 않습니다 whatever-xfoo. 위의 인용문은 의 특별한 의미를 제거 *하지만 .Nor의 특별한 의미를 제거하지는 않습니다 $.

더 간단한 동작 : 인용은 정규식 연산자(bash31에서와 같이)의 의미를 변경하지 않으므로 동작을 더 예측 가능하게 만듭니다(ERE(with ) zsh대신 PCRE 정규식을 사용할 수도 있음 ).set -o rematchpcre

yash[[...]]생성자 는 없지만 [연산자 =~가 내장되어 있습니다( 에도 있음 zsh). 물론 [일반 명령과 마찬가지로 인용은 정규식 연산자가 해석되는 방식에 영향을 주지 않습니다.


또한 엄밀히 말하면 $s3줄이 아닌 2줄의 완전한 줄과 끝나지 않은 줄이 포함되어 있다는 점에 유의하세요. 그것은 포함되어 있습니다 hello\nworld\nOK. OK$확장 정규식 에서 $연산자는 마지막 항목만 일치합니다..

총 3줄로, 예를 들어 hello\nworld\nOK\n(명령 대체를 사용하면 명령 대체 표시줄을 얻을 수 없습니다)모두후행 개행)은 $이후에 일치하므로 \n일치 OK$하지 않습니다.

그러나 에 플래그를 전달하지 않기 때문에 문자열의 끝과 개행 문자 앞이 있는 경우 일치 zsh -o pcrematch합니다 .$PCRE_DOLLAR_ENDONLYpcre_compile일반적으로 셸의 변수에는 후행 개행 문자가 포함되어 있지 않으며, 포함된 경우 일반적으로 데이터로 처리되기를 원하기 때문에 이것은 나쁜 생각으로 보일 수 있습니다..

답변2

적어도 에서는 bashRHS를 인용하면 문자열 비교로 처리됩니다.

$ s=$(printf 'hello\nworld\nOK\n')
$ echo "$s"
hello
world
OK
$ [[ "$s" =~ OK$ ]] && echo "match" || echo "no match"
match

하지만

$ s=$(printf 'hello\nworld\nOK$\n')
$ echo "$s"
hello
world
OK$
$ [[ "$s" =~ 'OK$' ]] && echo "match" || echo "no match"
match

답변3

잘 알려지지 않은 사실: case그것도 마찬가지입니다.

case "$(printf 'hello\nworld\nOK\n')" in
  *$'\nOK') echo "match";;
  *) echo "no match";;
esac

"C 스타일" 문자열 $'...'은 Bash 확장(셸 문자열에서 백슬래시 이스케이프 코드를 사용할 수 있는 컨텍스트를 제공 \n)이지만 이식성을 위해 다음과 같이 말할 수 있습니다.

*"
OK") echo "match";;

POSIX와 완전히 호환되는 쉘 스크립트를 얻으십시오.

그러나 명령문에서 사용할 수 있는 패턴은 case적절한 정규식이 아닌 쉘 글로브 패턴입니다.

관련 정보