[root@localhost opt]# cat cfg
key = value
[root@localhost opt]# grep 'key\s*=\s*.+' cfg
[root@localhost opt]#
내 의도는 다음과 같습니다. =
기호 뒤에는 0개 이상의 공백이 올 수 있지만 뒤에는 공백이 아닌 문자가 하나 이상 와야 합니다.
이 줄은 왜 출력되지 않습니까 key = value
?
답변1
관찰하다:
$ grep 'key\s*=\s*.+' cfg
$ grep 'key\s*=\s*.\+' cfg
key = value
$ grep -E 'key\s*=\s*.+' cfg
key = value
기본 정규식(BRE, 기본값)에서는 +
더하기 기호를 나타냅니다. GNU 확장으로서 하나 이상의 이전 문자를 나타내는 데 사용할 수 있습니다 \+
. ?
, {
, |
에도 마찬가지입니다 (
. 백슬래시로 이스케이프하지 않는 한 BRE에서는 일반 문자로 처리됩니다.
확장 정규식을 사용하면 규칙이 변경됩니다 -E
. ERE의 경우 백슬래시는 필요하지 않으며 일반적으로 +
하나 이상의 이전 문자를 나타냅니다. ERE에서는 \+
일반 일반 더하기 기호를 나타냅니다.
답변2
key\s*=\s*.+
GNU ERE 구문입니다( \s
공백 문자와 일치하고 +
하나 이상의 선행 원자와 일치한다고 가정). 따라서 GNU 구현이 필요 grep
하고 해당 -E
옵션을 전달합니다.
그러나 그것조차 별로 의미가 없다.
첫 번째
grep 'key\s*=\s*.+'
기능적으로 동일
grep 'key\s*=\s*.'
왜냐하면 문자열이 일치하면 anything.+
문자열도 일치 anything.
하고 그 반대도 마찬가지이기 때문입니다.
또한 공백 문자도 문자입니다. \s*
게임 이후로0이상의 공백 문자, key\s*=\s*.
기능적으로 key\s*=.
(line 포함 key<optional-spaces>=<one-character-space-or-not>
)과 동일합니다.
원하는 곳은 다음과 같습니다.
grep 'key\s*=\s*\S'
의 오른쪽에서 공백이 아닌 문자를 하나 이상 찾아야 하며 =
해당 기능은 다음과 동일합니다.
grep 'key\s*=.*\S'
또한 key = foo
일치하지만 nonkey = foo
. key
줄의 시작 부분에서만 찾으려면 앵커를 사용하여 다음을 요청해야 합니다 ^
.
grep '^key\s*=.*\S'
또는 -x
정규식을 사용하여 전체 줄을 일치시킵니다.
grep -x 'key\s*=.*\S.*'
에 해당하는 표준은 ( for ) \s
입니다 .[[:space:]]
[^[:space:]]
\S
이 요구 사항을 충족하는 또 다른 방법은 특정 정규식(예: PCRE)에서 스프레드 연산자를 사용하여 역추적을 방지하는 것입니다.
key=\s*.
key=
정규식 엔진이 \s*
다음 공백 문자를 탐욕스럽게 반복하여 1을 찾은 다음 줄 끝에 도달했기 때문에 =
일치할 수 없다는 것을 깨달았기 때문에 일치합니다 ..
역추적다음 일치 항목 (여기서는 공백 문자)이 일치할 수 \s
있도록 더 적은 일치 항목(이 경우 0)을 사용해 보십시오 ..
-P
GNU 옵션과 마찬가지로 PCRE를 사용하면 다음 과 같이 grep
작성할 수 있습니다.
grep -P '^key\s*=(?>\s*).'
이 (?>...)
구문은 역추적을 방지합니다. 따라서 \s*
역추적할 수 없는 상태에서 최대한 많은 공백 문자를 먹게 되므로 공백 뒤에 공백이 아닌 문자가 하나 이상 올 경우에만 일치가 발생합니다.
$ printf 'key=%s\n' '' ' ' ' a' | grep '^key\s*=\s*.'
key=
key= a
$ printf 'key=%s\n' '' ' ' ' a' | grep -P '^key\s*=(?>\s*).'
key= a
$ printf 'key=%s\n' '' ' ' ' a' | grep '^key\s*=.*\S'
key= a