`^[ ]{0,}`가 Linux grep에서 작동하지 않는 이유는 무엇입니까?

`^[ ]{0,}`가 Linux grep에서 작동하지 않는 이유는 무엇입니까?

이것은 내 샘플 텍스트입니다. grep w, 매우 잘 작동합니다 grep ^w.grep '^[ ]w'

[user@linux ~]$ grep w text.txt
whitespace 0
 whitespace 1
  whitespace 2
[user@linux ~]$

[user@linux ~]$ grep ^w text.txt
whitespace 0
[user@linux ~]$

1개의 공간이 있습니다

[user@linux ~]$ grep '^[ ]w' text.txt
 whitespace 1
[user@linux ~]$

공백이 2개 있지만 동일한 출력을 얻습니다.

[user@linux ~]$ grep '^[  ]w' text.txt
 whitespace 1
[user@linux ~]$

~에 따르면https://regex101.com/^[ ]{0,}줄 시작 부분에서 공백을 찾는 올바른 구문입니다. 그러나 Linux의 GNU grep에서는 제대로 작동하지 않습니다. 오류가 발생합니다 Invalid regular expression.

[user@linux ~]$ grep ^[ ]{0,}w text.txt
grep: Invalid regular expression
[user@linux ~]$

이것들은 전혀 아무것도 반환하지 않습니다

[user@linux ~]$ grep '^[ ]{0}w' text.txt
[user@linux ~]$ grep '^[ ]{1}w' text.txt
[user@linux ~]$ grep '^[ ]{2}w' text.txt
[user@linux ~]$ grep '^[ ]{0,}w' text.txt
[user@linux ~]$

질문: ^[ ]{0,}GNU grep과 함께 사용할 수 있나요? 그렇다면 이전 문법에 어떤 문제가 있었나요?

답변1

여기에는 온갖 종류의 문제가 있습니다. 첫째, 표현식의 ^[ ]w의미는 다음과 같습니다. 줄의 시작 부분을 찾은 다음 정확히 하나의 공백을 찾은 다음 하나를 찾습니다 w. 그래서 실제로 꽤 잘 작동합니다. 하나 이상의 공백과 일치하도록 하려면 [ ]문자 클래스에 한정자를 추가해야 합니다.

  $ grep '^[  ]\+w' text.txt
 whitespace 1
  whitespace 2

+"하나 이상"을 의미합니다 . 사용되는 기본 정규식 스타일은 grepBRE(기본 정규 표현식)라고 하며 이 정규식 스타일에서는 +이스케이프가 필요하므로 \+위의 * . 또는 플래그를 전달하여 ERE(확장 정규 표현식)를 사용 -E하거나 -P플래그를 전달하여 PCRE(Perl 호환 정규 표현식)을 사용할 수 있습니다. 이러한 정규식 스타일을 사용하면 +수량자 역할을 하기 위해 이스케이프할 필요가 없습니다 .

$ grep -P '^[  ]+w' text.txt
 whitespace 1
  whitespace 2
$ grep -E '^[  ]+w' text.txt
 whitespace 1
  whitespace 2

다음 문제이자 더 중요한 문제는 정규식을 인용하지 않는다는 것입니다. 정규 표현식이 전달되도록 하려면 따옴표가 필요합니다.grep 있는 그대로쉘에 의해 먼저 해석되지 않습니다. 그러나 인용하지 않았으므로 에 전달되기 전에 셸에 의해 확장됩니다 grep. set -x쉘이 수행 중인 작업을 인쇄하도록 하는 옵션을 사용하여 이를 확인할 수 있습니다 :

$ set -x
$ grep ^[ ]{0,}w text.txt
+ grep '^[' ']0w' ']w' text.txt
grep: Invalid regular expression

^[첫째, 및 사이에 공백이 있기 때문에 ]쉘은 이를 두 개의 별도 인수인 ^[및 로 해석합니다 ]{0,}w. 그러나 {}버팀대 확장을 위해 쉘에서 사용됩니다. 예를 들어:

$ echo foo{a,b}
fooa foob

그러나 확장의 두 번째 부분이 비어 있으면 다음과 같은 결과가 나타납니다.

$ echo foo{a,}
fooa foo

따라서 확장은 다음 ]{0,}w과 같습니다.

$ echo ]{0,}w
]0w ]w

결과적으로 set -x위 출력에서 ​​볼 수 있듯이 이 세 가지 매개변수는 실제로 다음으로 전달됩니다 grep.

'^[' ']0w' ']w'

그러나 인용하는 경우 +위와 같이 BRE를 사용할 때 이스케이프 처리해야 합니다.

$ grep '^[ ]\{2\}w' text.txt
  whitespace 2

마지막 참고 사항: [ ]정확히 똑같습니다 . 개별 문자에 대해 문자 클래스를 사용하는 것은 의미가 없습니다.

이 모든 것을 종합하여 줄 시작 부분에서 정확히 하나의 공백과 일치하려면 다음을 사용하십시오.

$ grep '^ w' text.txt 
 whitespace 1

하나 이상을 일치시키려면 다음을 사용하십시오.

$ grep '^ \+w' text.txt 
 whitespace 1
  whitespace 2

또는:

$ grep -E '^ +w' text.txt 
 whitespace 1
  whitespace 2

또는

$ grep -P '^ +w' text.txt 
 whitespace 1
  whitespace 2

특정 숫자 범위(예: 공백 0, 1, 2개)와 일치시키려면 다음을 수행하세요.

$ grep '^ \{0,3\}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

또는

$ grep -P '^ {0,3}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

또는

$ grep -E '^ {0,3}w' text.txt 
whitespace 0
 whitespace 1
  whitespace 2

특정 숫자와 일치시키려면 {}위에 표시된 대로 숫자를 설정하거나 문자를 N번 반복하십시오.

$ grep '^ \{2\}w' text.txt
  whitespace 2
$ grep '^ w' text.txt
 whitespace 1
$ grep '^  w' text.txt
  whitespace 2

그리고항상 정규식을 인용하세요!


* 실제로 POSIX BRE에서는 +특별한 의미가 없지만 BRE의 GNU 구현은 grep이스케이프되면 이를 인식합니다.

답변2

BRE에서는 욕심 많은 수량자 표현식에서 {0,}원하는 정규식 일치를 달성하려면 중괄호를 이스케이프해야 하며 항상인용하다정규식 문자열. 따옴표가 없으면 셸은 제공된 인수에 자체 구문 분석 구문을 적용하려고 시도하며 대부분의 경우 인수는 정규식의 일부만 grep표시되도록 토큰화됩니다 .^[

grep '^[ ]\{0,\}w' file

~에서정규식 참조: 수량자그리고 GNU BRE를 선택하세요

\{n,\}n >= 0이전 항목 중 하나 이상이 반복 됩니다 n. 욕심쟁이(Greedy)이므로 이전 항목이 n번만 일치할 때까지 가능한 한 많은 항목을 일치시킨 후 이전 항목이 덜 일치하는 순열을 시도합니다.

주석에서 지적했듯이 using 은 *modifier 를 사용하는 것과 동일합니다 \{0,\}.

답변3

올바른 명령:

사용grep -E '^[ ]{0,}' text.txt

-E, --extended-regexp PATTERN을 확장 정규식(ERE, 아래 참조)으로 해석합니다.

작동하지 않는 이유:

정규식 주위에 작은따옴표를 사용하지 마십시오. bash가 이를 열고 명령은 다음과 같습니다.

grep '^[' ] ]0 text.txt정규식을 사용하여 grep '^['파일 로 변환됩니다 ].]0text.txt

^[[특수 문자에도 종료 문자가 필요하기 때문에 잘못되었습니다.]

-E 옵션이 필요한 이유:

{m,n}은 확장 정규 표현식입니다. 이를 사용하려면 grep에 -E 옵션이 필요합니다.

관련 정보