최신그렙 3.8백슬래시로 이스케이프 처리된 공백이 있는 패턴에 대해 경고
$ grep "bla\ bazz" t
/tmp/bin/grep: warning: stray \ before white space
...
그리고 grep 3.6은 불평하지 않습니다. 이 패턴을 처리하는 올바른 방법은 무엇입니까? 그냥 공간에서 탈출하지 마세요? 즉
$ grep "bla bazz" t
grep
이스케이프되지 않은 공간을 잘못 처리하는 좀 더 이국적인 가 있습니까 ? 어쩌면 모든 것을 깔끔하고 깔끔하게 만들기 위해 다른 할당량을 사용할까요?
답변1
공백 문자는 정규 표현식에서 특별하지 않으므로( perl
이 플래그가 활성화된 -like 표현식 제외 x
) 이스케이프되어서는 안 됩니다. \
공백을 따르면 POSIX 정규식에서 지정되지 않은 결과가 생성됩니다.
그래서 당신은 다음을 원합니다:
grep 'blah bazz'
더 명확하게 만들고 싶다면 다음을 사용할 수 있습니다.
grep 'blah[ ]bazz'
\
보다 일반적으로 는 정규식 연산자가 아닌 문자 앞에 is를 넣으면 안 됩니다 . X
정규식 연산자는 아니지만 지금 \X
은 아니더라도 향후 버전에 있을 가능성이 높습니다. 예를 들어, +
, <
는 d
기본 정규식 연산자가 아니지만 일부 구현에서는 \<
, \+
및 \d
가 사용됩니다 grep
.
\
다음과 같은 경우에는 후행 공백을 사용해야 할 수도 있습니다 .
grep -P '(?x) foo \ bar'
perl -ne 'print if / foo \ bar /x'
foo bar
x
플래그가 켜져 있을 때 일치가 발생합니다 . 하지만 그때에도 당신은 이것을 하고 싶어합니다:
grep -P '(?x) foo [ ] bar'
더 읽기 쉽게 만들기 위해. 이 플래그의 전체 목적은 x
정규식을 더 명확하게 만드는 것입니다. 예를 들면 다음과 같습니다.
perl -ne 'print if m{
\d{4} # year
- \d{2} # month
- \d{2} # day
[ ] (foo | bar | baz)}x'
그리고
perl -ne'print if/\d{4}-\d{2}-\d{2} (foo|bar|baz)/'
그러나 대괄호 표현식 내부의 공백도 무시되는 플래그(PCRE가 아닌 Perl 5.26+에서는) [ ]
와 함께 사용할 수 없습니다 .xx
perldoc perlre
Perl 정규식 및 man pcrepattern
PCRE(Perl 호환 정규식)에 대한 자세한 내용은 참고자료를 참조하세요. 사용하는 \Q \E
것은 또 다른 옵션입니다.
어쨌든 공백은 셸 구문에서는 특수 문자이지만 정규식에서는 특수 문자가 아니지만 , *
, \
, (
, , )
, , , , ?
, , , , , , , , , , $
, ^
, [
, ]
, 과 같이 두 구문 모두에 특수 문자인 문자가 많이 있으므로 두 if는 다음과 같습니다. 문자 그대로 일치하는 것을 의미하며, 바람직하게는 셸 주변의 따옴표로 묶고 \
(또는 [...]
펄 \Q...\E
과 같은 경우에는) 정규 표현식을 표현합니다.
및 \
는 $
정규식에서 일반적이고 이러한 문자는 여전히 큰따옴표 안의 셸에 특별하므로 정규식을 큰따옴표보다는 작은따옴표로 묶는 것이 좋습니다. 셸 매개변수를 정규식으로 확장해야 하거나 정규식에 a를 포함 grep "^$var"
해야 하는 경우에만 큰따옴표를 사용하면 됩니다.'
정규식과 반대되는 리터럴 문자열 grep
, 즉 이스케이프된 문자열입니다.모든정규식 연산자의 경우 -F
( F
고정 문자열용) 옵션 을 사용할 수 있습니다 grep
. 예를 들어:
grep -F 'blah\ bazz'
포함된 항목을 찾습니다 blah\ bazz
.
답변2
셸에서 공백을 보호하기 위해 공백을 이스케이프하면 됩니다 grep
. 공백 문자는 정규식에 특별하지 않으며 셸에서 인수를 정의하는 데 사용하는 문자이기 때문에 셸에서만 특별합니다. 따라서 패턴이 인용되지 않은 경우(나쁜 생각임) 공간이 필요합니다.
$ echo 'foo bar' | grep -c foo\ bar
1
이렇게 하면 쉘이 파일 이름으로 foo bar
전달된 두 인수를 구문 분석하지 않습니다 . 다음을 사용하여 이를 확인할 수 있습니다 .bar
grep
set -x
$ set -x
$ echo 'foo bar' | grep -c foo\ bar
+ grep -c 'foo bar'
+ echo 'foo bar'
1
탈출하지 못하면 다음을 얻습니다.
$ echo 'foo bar' | grep -c foo bar
+ grep -c foo bar
+ echo 'foo bar'
grep: bar: No such file or directory
그러나 패턴을 인용하면 셸로부터 패턴이 보호되며 이스케이프가 필요하지 않습니다.
$ echo 'foo bar' | grep -c "foo bar"
+ grep --color -c 'foo bar'
+ echo 'foo bar'
1
또는
$ echo 'foo bar' | grep -c 'foo bar'
+ grep --color -c 'foo bar'
+ echo 'foo bar'
1
그렇기 때문에 이제 공백 앞에 리터럴(인용문)이 표시 grep
되면 경고합니다 . \
\
탈출할 항목이 없으므로
\
의미가 없기 때문에 방금 (space)가 되었다고 경고합니다. "이스케이프 가능"하지 않은 경우 이스케이프된 다른 문자에 대해 동일한 작업을 수행합니다.
$ echo 'foo bar' | grep -c "f\oo\ bar"
+ grep --color -c 'f\oo\ bar'
+ echo 'foo bar'
grep: warning: stray \ before o
grep: warning: stray \ before white space
1
답변3
3.8 릴리스 노트부터 시작합니다(https://savannah.gnu.org/news/?id=10191):
흩어진 백슬래시가 있는 정규식은 이제
지정되지 않은 동작으로 인해 예상치 못한 결과가 발생할 수 있으므로 경고를 발생시킵니다. 예를 들어 '\a'와 'a'가 항상 동일한 것은 아닙니다.
https://bugs.gnu.org/39678. 마찬가지로,
반복 연산자로 시작하는 정규 표현식이나 하위 표현식도
지정되지 않은 동작으로 인해 경고를 발생시킵니다. 예를 들어 *a(+b|{1}c)에는
이제 세 가지 경고 이유가 있습니다. 이러한 경고는
임시 지원을 위한 것입니다 . 향후 릴리스에서는 버그가 발생할 수 있습니다.