grep의 정규식에서는 이스케이프 문자를 인용해야 하지만 온라인 정규식 엔진에서는 인용하지 말아야 하는 이유는 무엇입니까?

grep의 정규식에서는 이스케이프 문자를 인용해야 하지만 온라인 정규식 엔진에서는 인용하지 말아야 하는 이유는 무엇입니까?

나는 이 질문의 일부 버전이 이전에 질문되고 답변되었다고 확신하지만 주위를 둘러보았지만 명확한 답을 찾지 못했습니다. 어쩌면 여기 누군가가 전구를 켜는 것을 도와줄 수도 있을 것 같아요. 저는 Mojave 10.14.6 및 bash 3.2.57(1) 릴리스가 설치된 Mac을 사용하고 있습니다.

온라인 튜토리얼을 통해 정규식의 기초를 배우고, 온라인 웹사이트에서 연습하고 있습니다.https://regexr.comgrep, 그리고 내 로컬 컴퓨터의 bash에서 사용하세요.

저는 다음 세 가지를 포함하는 작은 텍스트 파일(small.txt라고 함)을 사용하여 연습을 하고 있습니다.

9.00
9-00
9500

.와일드카드는 해당 위치의 모든 문자와 일치한다는 것을 알고 있습니다 . 따라서 제가 사용하고 있는 온라인 정규식 엔진(JavaScript)에서는 /9.00/g세 문자열 9.00 9-009500.

grep명령줄에서 사용하면 효과는 동일합니다.

~/bin $ grep 9.00 small.txt
9.00
9-00
9500

여태까지는 그런대로 잘됐다. 튜토리얼에서는 .메타 문자를 리터럴로 변환하려면 이를 이스케이프해야 한다고 말합니다. 좋아요 따라서 예상대로 온라인 정규식 상자에 넣으면 9-00 또는 9500 /9\.00/g만 일치합니다 . 9.00기이.

그러나 명령줄에 동일한 구문을 입력하면 grep예상치 못한 결과가 나타납니다.

~/bin $ grep 9\.00 small.txt
9.00
9-00
9500

이전과 같습니다. 작동하게 하려면 grep전체 문자열을 큰따옴표로 묶어야 합니다.

~/bin $ grep "9\.00" small.txt
9.00

또는 큰따옴표 이스케이프 문자만 사용하면 됩니다.

~/bin $ grep 9"\."00 small.txt
9.00

올바른 결과를 제공하는 다른 인용 선택을 할 수도 있을 것입니다.

이로 인해 정규식의 기본을 이해하기가 어렵습니다. 왜냐하면 분명히 먼저 grep셸에서 이를 수행하는 방법을 이해해야 하기 때문입니다.다른전통적인 정규식 구문에서. 정규식의 모든 규칙을 배우는 것만으로도 충분히 어렵지만, 고전적인 정규식과 bash 쉘 동작의 차이점을 추가하면 머리가 터질 것 같습니다.

어쨌든, 이 문제를 해결하고 명령줄에서 grep과 함께 사용할 수 있는 정규식을 올바르게 배우는 데 도움이 될 수 있는 명확한 설명이 있는지 궁금합니다.

(정규식에 대한 과정 중 어느 것도 grep과 bash의 명령줄 버전과 온라인 정규식 테스터에서 볼 수 있는 "순수한" 정규식 구문 간의 차이점을 지적하지 않습니다.) 엔진 고급 수준 간에 차이가 있다는 것을 알고 있지만 이는 다음과 같습니다. 매우 기본적인 내용인데 뭔가 빠진 것 같은 느낌이 듭니다.

감사해요.

답변1

왜? 쉘이 \예제에 나온 것과 같은 일부 특수 문자를 해석하기 때문입니다.

쉘을 통해 grep하기 위한 인수로 전달하려는 문자열을 보호하지 않기 때문에 문제가 발생합니다.

여러 가지 솔루션:

  • 작은따옴표 문자열,
  • 큰따옴표로 묶인 문자열(큰따옴표를 사용하면 쉘은 $variables결과 문자열을 명령에 보내기 전에 무언가를 해석합니다),
  • 또는 따옴표를 사용하지 말고(강력히 권장하는) 백슬래시를 올바른 위치에 추가하여 쉘이 명령에 보내기 전에 다음 문자를 해석하지 못하도록 하십시오.

거의 모든 것을 보존하므로 작은따옴표로 문자열을 보호하는 것이 좋습니다.

grep '9\.0' #send those 4 characters to grep in a single argument

쉘은 작은따옴표로 묶인 문자열을 문자 그대로 전달합니다.

참고: 작은따옴표로 묶인 쉘 문자열에 포함될 수 없는 유일한 것은 작은따옴표입니다(이렇게 하면 작은따옴표가 종료되기 때문입니다). 작은따옴표로 묶인 쉘 문자열에 작은따옴표를 포함하려면 먼저 작은따옴표를 끝내고 즉시 이스케이프된 작은따옴표 \'(또는 큰따옴표 사이에 : "'")를 추가한 다음 즉시 작은따옴표를 다시 입력하여 작은따옴표를 계속해야 합니다. - 따옴표 붙은 문자열: 예를 들어 쉘이 명령을 실행하도록 하려면 쉘이 grep으로 보낼 grep a'b인수를 작성할 수 있습니다 .'a'\''b'a'bgrep 'a'\''b'grep 'a'"'"'b'

따옴표를 사용하지 않으려면 쉘에 a를 \\보내서 \grep으로 보내야 합니다.

grep 9\\.0  # ie: a 9, a pair \\, a ., and a 0 , and the shell interprets the pair \\ into a literal \

$vars큰따옴표를 사용하는 경우: 쉘이 먼저 몇 가지 사항( 등 ) 을 해석한다는 점을 고려해야 합니다 \. 예를 들어, 이스케이프되지 않거나 인용되지 않은 을 보면 \다음 문자가 이를 해석하는 방법을 결정할 때까지 기다립니다. \w단일 문자로 처리됨 w, \\단일 문자로 처리됨 \

grep "9\\.0"  # looks here the same as not quoting at all... 
    #but doublequoting allows you to have spaces, etc, inside the string

답변2

댓글을 답변으로 변환:

문제는 이것이 \정규식이자 쉘 이스케이프 문자라는 것입니다. \.쉘과 동일합니다 '.'. 쉘의 역할을 이해하는 데 도움이 되도록 다음을 수행하십시오 echo.set -x

> echo \.
.

> echo '\.'
\.

> echo \\.
\.


> set -x
> echo 9_00 | grep 9\.00
+ echo 9_00
+ grep 9.00
9_00

따라서 명령을 표시하려면 \따옴표나 두 번째 따옴표로 보호해야 합니다 \.

답변3

다른 답변과 의견을 추가하려면 grep다음 명령을 사용하여 원하는 것을 반환하는 것입니다.

grep -F 9.00 small.txt

산출:

9.00

make는 패턴을 정규 표현식이 아닌 고정 문자열로 -F처리하므로 grep정확한 문자열이 있는 행만 반환합니다. 따라서 정확히 일치하기만 하고 문자 로 처리되지 않으므로 이스케이프 처리 .하거나 따옴표를 사용할 필요조차 없습니다 .9.00.

답변4

grep의 정규식에서는 이스케이프 문자를 인용해야 하지만 온라인 정규식 엔진에서는 인용하지 말아야 하는 이유는 무엇입니까?

굳이 인용할 필요는 없어grep, 그러나 쉘의 경우.

grep -f파일에서 패턴 읽기를 사용하면 9\.00표시된 패턴이 셸을 통과하지 않아도 제대로 작동한다는 것을 알 수 있습니다.

$ cat re.txt 
9\.00
$ grep -f re.txt small.txt 
9.00

실제로 문제 grep자체는 문제가 아니므로 정규식에 대한 기사에서 해당 문제를 볼 수 없는 것일 수 있습니다. 그러나 쉘 작동 방식에 대한 기사에서 관련 사항을 볼 수 있습니다.

프리미엄 엔진에는 차이가 있다는 것을 알고 있습니다.

너무 발전할 필요도 없습니다. +BRE 및 ERE의 유사한 기능이 변경되었습니다. 또한 적어도 일부 온라인 도구는 기본적으로 Perl 정규식 또는 유사한 도구를 사용하는데, 이는 표준 정규식에서 찾을 수 없는 많은 기능을 가지고 있습니다.

바라보다:

관련 정보