Grep : 별표 (*)가 항상 작동하지는 않습니다


11

다음을 포함하는 문서를 grep하면

ThisExampleString

... This*String또는 표현식의 *String경우 아무것도 반환되지 않습니다. 그러나 This*예상대로 위의 행을 반환합니다.

표현식이 따옴표로 묶여 있는지 여부는 차이가 없습니다.

별표에 알 수없는 문자가 몇 개나 있다고 생각합니까? 표현식이 시작될 때만 작동하는 이유는 무엇입니까? 이이 동작을 목적으로하는 경우, 내가 대신 표현의 사용합니까 This*String*String?


왜냐하면 정규 표현식이 작동하는 방식이 아니기 때문에 ... (특히 : * != any number of unknown characters문서를 읽으십시오.)
njzk2

답변:


18

정규 표현식 에서 별표 는 "앞의 요소를 0 번 이상 일치"를 의미합니다.

의 경우에는 grep 'This*String' file.txt"이봐, grep, 나에게 단어를 일치시키고 Thi, 소문자 s0 번 이상 , 뒤에 단어"를 말하려고합니다 String. 소문자 s는 어디에도 없으므로 Examplegrep은 무시합니다 ThisExampleString.

의 경우에 grep '*String' file.txt, 당신은 "그리프, 단어 앞에있는 빈 문자열 (문자 그대로 아무것도 없음)"을 말하는 것 String입니다. 물론, 그렇게 ThisExampleString읽는 것이 아닙니다 . ( 플래그를 사용하거나 사용하지 않고 시도 할 수 있는 다른-E 의미가 있지만 여기서 실제로 원하는 것과 다른 의미는 없습니다.)

."단일 문자" 를 의미 한다는 것을 알면 다음 과 같이 할 수 grep 'This.*String' file.txt있습니다. 이제 grep 명령은 올바르게 읽습니다. This그 뒤에는 여러 번 반복되는 모든 문자 (ASCII 문자 선택으로 생각)가 이어집니다 String.


6
Bash (및 대부분의 유닉스 쉘) *는 특수 문자이며 예기치 않은 결과에 놀라지 않도록 grep 'This*String' file.txt다음 과 같이 인용하거나 이스케이프해야합니다 grep This\*String file.txt.
pabouk

2
셸에서 @pabouk은 *와일드 카드입니다. grep에서 *정규 표현식 연산자입니다. 참조 unix.stackexchange.com/q/57957/70524
muru

11
pabouk이 맞습니다. 명령 실행 전에 파일 이름 확장이 수행됩니다. strace grep .* file.txt |& head -n 1 와 비교하십시오 strace grep '.*' file.txt |& head -n 1. 또한 실제로 grep모든 유니 코드 문자 (예 : echo -ne ⇏ | grep ⇏출력 ) 와도 작동합니다.
kos

1
@ Serg : 당신은 여기에서 높은 명성을 얻었으므로 즉시 의미하는 것을 알 것이라고 생각했습니다. OP는 질문 bash에 태그를 달았 으므로 논의 된 명령이에 의해 해석된다고 가정합니다 bash. 즉, 먼저 bash특수 문자를 해석하고 모든 확장을 수행 한 후에 만 ​​매개 변수를 생성 된 프로세스로 전달합니다. ----- 예를 들어 Bash :에서이 명령은 0 : , 1 : , 2 : 이 매개 변수와 함께 grep This.\*String file.txt생성 /bin/grep됩니다 . Bash는 백 슬래시를 제거했고 원래 이스케이프 는 그대로 문자 그대로 전달되었습니다. grepThis.*Stringfile.txt*
pabouk

7
우스운 (그리고 꽤 불쾌한 문제를 해결하기위한 것) : grep This.*String file.txt쉘 와일드 카드 식과 일치하는 파일이 없기 때문에 같은 명령 이 정상적으로 작동한다는 것 This.*String입니다. 이 경우 기본적으로 Bash는 문자 그대로를 포함하는 인수를 전달합니다 *.
pabouk

8

*BRE에서 메타 1 S, ERE 1 S 및 PCRE 하나 의 일치하는 미리 그룹화 패턴 0 이상의 OCCURENCES (그룹화 된 패턴이 선행되는 경우 *메타)에 이전 문자 클래스 0 이상의 OCCURENCES (문자 클래스이면 *메타 문자 앞 ) 또는 이전 문자의 0 개 이상의 발생 (그룹화 된 패턴이나 문자 클래스가 *메타 문자 앞에 있지 않은 경우 );

이는 This*String패턴에서 *메타 문자 앞에 그룹화 된 패턴이나 문자 클래스가없는 *메타 문자는 이전 문자 (이 경우 s문자)의 0 개 이상의 발생과 일치 함을 의미합니다.

% cat infile               
ThisExampleString
ThisString
ThissString
% grep 'This*String' infile
ThisString
ThissString

임의의 문자에서 0 개 이상의 발생을 일치 시키려면 임의의 문자와 일치하는 0 개 이상의 .메타 문자 발생을 일치 시키십시오 .

% cat infile               
ThisExampleString
% grep 'This.*String' infile
ThisExampleString

*BRE 및 ERE 의 메타 문자는 항상 "욕심"입니다. 즉 가장 긴 일치 항목과 일치합니다.

% cat infile
ThisExampleStringIsAString
% grep -o 'This.*String' infile
ThisExampleStringIsAString

원하는 동작이 아닐 수도 있습니다. 경우에 당신이 설정할 수 있습니다, 아니다 grep합니다 (사용의 PCRE 엔진을 -P옵션)과 추가 ?애프터 넣어 메타 문자 *+메타 문자는 자신의 탐욕을 변경하는 효과가 있습니다를 :

% cat infile
ThisExampleStringIsAString
% grep -Po 'This.*?String' infile
ThisExampleString

1 : 기본 정규 표현식, 확장 정규 표현식 및 Perl 호환 정규 표현식


유익한 정보에 감사드립니다. 그러나 나는 더 짧고 이해하기 쉽기 때문에 다른 대답을 선택했습니다. 많은 세부 정보를 제공하는 +1
Trae

@Trae 천만에요. 나는 이것이 너무 복잡하고 주제에 너무 익숙하지 않은 누군가를 위해 너무 많은 가정을 한 것에 동의합니다.
kos

4

여기에 설명 중 하나가 링크되어 있습니다 .

별표 " *"는 정규 표현에서 와일드 카드와 같은 의미가 아닙니다. 선행 단일 문자 또는 [0-9]와 같은 표현식에 적용되는 수정 자입니다. 별표는 앞에 오는 것 중 0 개 이상과 일치합니다. 따라서 하나 이상의 대문자와 일치 [A-Z]*하지만 없음을 포함하여 [A-Z][A-Z]*여러 대문자와 일치합니다.


1

*쉘 글 로빙 문자 ( "와일드 카드")와 정규식 메타 문자 모두에 특별한 의미가 있습니다 . 정규식 을 인용 하면 쉘이 특수하게 처리하지 못하게하고 변경되지 않은 상태로 전달되도록 할 수 grep있습니다. 개념적으로 비슷 하지만 *, 쉘에 의미하는 것은 그것이 의미하는 것과는 상당히 다릅니다 grep.

먼저 쉘은 *와일드 카드로 취급합니다 .

당신은 말했다 :

표현식이 따옴표로 묶여 있는지 여부는 차이가 없습니다.

명령을 실행할 때 어떤 디렉토리에 존재하는 파일에 따라 다릅니다. 디렉토리 구분 기호가 포함 된 패턴 /의 경우 전체 시스템에 존재하는 파일에 따라 달라질 수 있습니다. 당신은 항상해야 인용 에 대한 정규 표현식을 grep- 그리고 작은 따옴표는 일반적으로 best-- 있습니다 하지 않는 한 당신은 확실히 당신이 가진 괜찮있다 구 개 잠재적으로 놀라운 변환의 유형 쉘, 그렇지 않으면 수행 하기 전에 실행중인 grep명령을 사용합니다.

*인용 되지 않은 문자를 발견하면, "0 이상의 문자"를 의미 하고 그것을 포함하는 단어를 패턴과 일치하는 파일 이름 목록으로 대체합니다 . ( .패턴 자체가 시작 . 되거나 셸을 포함하도록 셸을 구성 하지 않는 한로 시작하는 파일 이름 은 제외됩니다 .)이를 globbing 이라고하며 파일 이름 확장명경로 이름 확장 이라고도합니다 .

그 효과 grep는 일반적으로 첫 번째 일치하는 파일 이름이 정규 표현식으로 사용되는 것입니다. 비록 인간 독자에게는 그것이 정규 표현식 이 아니라는 것이 명백하더라도 , 다른 모든 파일 이름은 자동으로 글로브는 파일로 촬영 내부의 일치를 검색합니다. (목록이 보이지 않습니다 grep. 이 파일은으로 불투명하게 전달됩니다 .) 실제로 이런 일이 일어나기를 원하지 않습니다.

이것이 때때로 문제 가 되지 않는 이유는 ( 그리고 적어도 지금까지는 그렇지 않은 경우), 다음 사항이 모두 해당 *경우 홀로 남겨질 것 입니다 .

  1. 이름이 일치하는 파일 이 없습니다 . ... 또는 일반적으로 set -f또는 이와 동등한 쉘에서 globbing을 비활성화했습니다 set -o noglob. 그러나 이것은 드문 일이며 아마도 당신이 그 일을했을 것입니다.

  2. *일치하는 파일 이름이 없을 때 기본 동작은 그대로 두는 쉘을 사용하고 있습니다. 이것은 아마도 Bash의 경우이며 아마도 모든 Bourne 스타일의 쉘에서는 사용하지는 않을 것입니다 . (예를 들어, 널리 사용되는 쉘 Zsh의 기본 동작은 globs가 (a) 확장 또는 (b) 오류를 생성하는 것입니다.) ... 또는 쉘의이 동작을 변경했습니다. 포탄을 가로 질러.

  3. 당신이하지 않은 다른 globs와가로 대체 할 수 있도록 쉘에게 아무것도 일치하는 파일이없는 경우,도이 상황에서 오류 메시지와 함께 실패 할 수 있습니다. Bash 에서 각각 nullglob또는 failglob shell 옵션 을 활성화하여 수행했을 것 입니다.

때로는 # 2와 # 3에 의존 할 수 있지만 # 1에 의존하는 경우는 거의 없습니다. grep인용 부호없는 패턴이 있는 명령은 다른 파일이 있거나 다른 위치에서 실행할 때 작동을 멈출 수 있습니다. 정규식을 인용하면 문제가 사라집니다.

그런 다음grep 명령 취급 *한정 기호로.

Sergiy Kolodyazhnyykos 와 같은 다른 답변 들도이 질문의이 측면을 다소 다른 방식으로 다루고 있습니다. 그래서 나는 아직 읽지 않은 사람들 이이 답변의 나머지 부분을 읽기 전후에 읽도록 ​​권장합니다.

*을 인용하여 인용해야 한다고 가정하면 인용 하는 항목이 정확히 한 번 발생하지 않고 여러 번 발생할 수 있음grep 을 의미합니다 . 여전히 한 번 발생할 수 있습니다. 또는 전혀 존재하지 않을 수도 있습니다. 또는 반복 될 수 있습니다. 와 맞 텍스트 어떤 사람들 가능성이 일치한다.

"항목"이란 무엇입니까?

  • 단일 문자 . 이후 b일치하는 문자는 b, b*0 또는 그 이상의 일치 b따라서들 ab*c과 일치하는 ac, abc, abbc, abbbc, 등

    마찬가지로, 이후 .일치하는 모든 문자 , .*0 개 이상의 문자와 일치 1 따라서, a.*c일치 ac, akc, ahjglhdfjkdlgjdfkshlgc,도 acccccchjckhcc, 등 또는

  • 문자 클래스 . 이후 [xy]일치 x하거나 y, [xy]*하나 하나가 어느 곳에 일치 이상의 문자를 제로 x또는 y따라서, p[xy]*q일치 pq, pxq, pyq, pxxq, pxyq, pyxq, pyyq, pxxxq, pxxyq, 등

    이것은 또한 적용 형태 나타내는 표현이 같은 문자 클래스의 \w, \W, \s,와 \S. \w모든 단어 문자와 \w*일치 하므로 0 개 이상의 단어 문자와 일치합니다. 또는

  • 그룹 . 이후 \(bar\)일치 bar, \(bar\)*일치는 0 이상의 barS, 따라서 foo\(bar\)*baz일치 foobaz, foobarbaz, foobarbarbaz, foobarbarbarbaz, 등

    -E또는 -P옵션을 사용하면 grep정규 표현식을 BRE가 아닌 각각 ERE 또는 PCRE 로 취급 한 다음 그룹이로 대신 둘러싸여 있으므로 대신 대신 및을 사용 합니다.( )\( \)(bar)\(bar\)foo(bar)bazfoo\(bar\)baz

man grep마지막에는 BRE 및 ERE 구문에 대한 합리적인 액세스 설명과 grep처음에 허용되는 모든 명령 줄 옵션을 나열합니다 . 나는 자원으로 그 매뉴얼 페이지, 또한 추천 은 GNU 그렙 문서튜토리얼 / 참조 사이트 (나는 위의 페이지의 번호로 연결 한).

테스트와 학습을 위해서는 grep파일 이름이 아닌 패턴으로 호출하는 것이 좋습니다. 그런 다음 터미널에서 입력을받습니다. 줄을 입력하십시오; 다시 에코되는 라인은 패턴과 일치하는 텍스트를 포함하는 라인입니다. 종료하려면 라인의 시작 부분에서 Ctrl+ D를 눌러 입력 끝을 알립니다. 또는 대부분의 명령 줄 프로그램에서와 같이 Ctrl+ C를 누를 수 있습니다. 예를 들면 다음과 같습니다.

grep 'This.*String'

--color플래그 를 사용하면 정규 표현식과 일치하는 라인 grep의 특정 부분 을 강조 표시 하여 정규 표현식의 기능을 파악하고 한 번 한 번 찾고있는 것을 찾는 데 매우 유용합니다. 기본적으로 Ubuntu 사용자는 명령 줄에서 grep --color=auto실행할 때 실행되도록 하는 Bash 별칭을 가지 grep므로 --color수동으로 전달할 필요도 없습니다 .

1 따라서 .*어떤 정규 표현식 수단의 *수단 쉘 글로브한다. 그러나 차이가 있다는 것입니다 grep자동으로 매치 포함하는 행을 출력 어디서나 그것을 가지고 일반적으로 불필요한 그래서, 그들을 .*정규 표현식의 시작이나 끝 부분에 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.