나는 이 질문의 일부 버전이 이전에 질문되고 답변되었다고 확신하지만 주위를 둘러보았지만 명확한 답을 찾지 못했습니다. 어쩌면 여기 누군가가 전구를 켜는 것을 도와줄 수도 있을 것 같아요. 저는 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-00
과 9500
.
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'b
grep '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 정규식 또는 유사한 도구를 사용하는데, 이는 표준 정규식에서 찾을 수 없는 많은 기능을 가지고 있습니다.
바라보다: