여러 줄 문자열이 지정된 패턴을 포함하는 줄로 끝나는지 확인하고 싶습니다.
이 코드는 실패하고 일치하지 않습니다.
s=`echo hello && echo world && echo OK`
[[ "$s" =~ 'OK$' ]] && echo match
답변1
bash
3.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
.zsh
ksh93
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
). 물론 [
일반 명령과 마찬가지로 인용은 정규식 연산자가 해석되는 방식에 영향을 주지 않습니다.
또한 엄밀히 말하면 $s
3줄이 아닌 2줄의 완전한 줄과 끝나지 않은 줄이 포함되어 있다는 점에 유의하세요. 그것은 포함되어 있습니다 hello\nworld\nOK
. OK$
확장 정규식 에서 $
연산자는 마지막 항목만 일치합니다.끈.
총 3줄로끈, 예를 들어 hello\nworld\nOK\n
(명령 대체를 사용하면 명령 대체 표시줄을 얻을 수 없습니다)모두후행 개행)은 $
이후에 일치하므로 \n
일치 OK$
하지 않습니다.
그러나 에 플래그를 전달하지 않기 때문에 문자열의 끝과 개행 문자 앞이 있는 경우 일치 zsh -o pcrematch
합니다 .$
PCRE_DOLLAR_ENDONLY
pcre_compile
일반적으로 셸의 변수에는 후행 개행 문자가 포함되어 있지 않으며, 포함된 경우 일반적으로 데이터로 처리되기를 원하기 때문에 이것은 나쁜 생각으로 보일 수 있습니다..
답변2
적어도 에서는 bash
RHS를 인용하면 문자열 비교로 처리됩니다.
$ 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
적절한 정규식이 아닌 쉘 글로브 패턴입니다.