grep 패턴에서 공백을 처리하는 올바른 방법

grep 패턴에서 공백을 처리하는 올바른 방법

최신그렙 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 barx플래그가 켜져 있을 때 일치가 발생합니다 . 하지만 그때에도 당신은 이것을 하고 싶어합니다:

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 perlrePerl 정규식 및 man pcrepatternPCRE(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전달된 두 인수를 구문 분석하지 않습니다 . 다음을 사용하여 이를 확인할 수 있습니다 .bargrepset -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)에는
이제 세 가지 경고 이유가 있습니다. 이러한 경고는
임시 지원을 위한 것입니다 . 향후 릴리스에서는 버그가 발생할 수 있습니다.

관련 정보