파일의 문자열을 일치시키기 위해 GNU grep
PCRE 정규식 지원을 사용하고 있습니다 . -P
입력 파일에는 다음 문자열이 포함된 줄이 포함되어 있습니다.
FOO_1BAR.zoo.2.someString:More-RandomString (string here too): 0.45654343
위 행의 숫자 2
와 숫자를 캡처하고 싶습니다. 0.45654343
정규식을 사용했어요
grep -Po ".zoo.\K[\d+](.*):\ (.*)$" file
하지만 나에게 있어서 결과는
2.someString:More-RandomString (string here too): 0.45654343
첫 번째 캡처 그룹에서 첫 번째 숫자를 가져올 수 2
있으며 줄 끝의 캡처 그룹과도 일치시킬 수 있습니다. 하지만 두 캡처 그룹 사이의 단어/줄을 건너뛸 수는 없습니다.
저는 (.*)
이 단어들을 중간에 포착하고 있는 그룹이 있다는 것을 알고 있습니다. 내가 하려는 것은 \K
그것을 무시하기 위해 다른 것을 포함시키는 것입니다.
grep -Po ".zoo.\K[\d+](.*):\K (.*)$" file
하지만 이것은 나에게 두 번째 캡처 그룹을 0.556984
.
(?:)
구문이 다음 과 같은 비캡처 그룹도 있습니다.
grep -Po ".zoo.\K[\d+](?=.someString:More-RandomString (string here too)):\ (.*)$"
그러나 그것은 나에게 아무것도 가져오지 못했습니다. 내가 여기서 무엇을 놓치고 있는 걸까요?
답변1
grep
이름은 g/re/p
ed
명령 뒤에 나타납니다. 주요 목적은 정규식과 일치하는 행을 인쇄하는 것입니다. 그 작업은 이 줄의 내용을 편집하는 것이 아닙니다. 당신은 sed
(스트림 편집기) 또는 awk
이것을 위해 있습니다.
이제 grep
GNU부터 일부 구현에서는 각 줄의 일치하는 부분(캡처링 그룹의 일치하는 부분이 아니라 정규식이 일치하는 부분)을 인쇄하는 옵션을 grep
추가합니다 . -o
이미 grep
GNU와 유사한 구현( 사용 -P
) 또는 pcregrep
PCRE에 대한 정규식 지원이 있습니다.
pcregrep
실제로 -o<n>
캡처 그룹의 내용을 인쇄하는 옵션이 추가되었습니다. 그래서 당신은 이것을 할 수 있습니다 :
pcregrep -o1 -o2 --om-separator=' ' '.zoo.(\d+).*:\s+(.*)'
그러나 여기서 확실한 표준 솔루션은 다음을 사용하는 것입니다 sed
.
sed -n 's/^.*\.zoo\.\([0-9]\{1,\}\).*:[[:space:]]\{1,\}/\1 /p'
또는 perl 정규식을 원하면 perl을 사용하십시오.
perl -lne 'print "$1 $2" if /\.zoo\.(\d+).*:\s+(.*)/'
GNU를 사용하여 grep
일치 항목이 다른 줄에 나타나는 것이 마음에 들지 않으면 다음을 수행할 수 있습니다.
$ grep -Po '\.zoo\.\K\d+|:\s+\K.*' < file
2
0.45654343
일치하는 구간의 시작 부분이 재설정된다고 해서 \K
교대로 겹치는 두 구간을 제거할 수 있는 것은 아닙니다.
grep -Po '.zoo.(\K\d+|.:\케이.)'
작동하지 않습니다. 작동하지 않습니다( 및 echo foobar | grep -Po 'foo|foob'
둘 다 인쇄 ). 먼저 일치한 다음 이후 입력에서 잠재적인 다른 일치 항목을 찾습니다 . 따라서 of로 시작하므로 그 이후에는 더 이상 일치하는 항목을 찾을 수 없습니다.foo
foob
foo|foob
foo
grep
foo
b
bar
위에서 우리는 grep -Po '\.zoo\.\K\d+|:\s+\K.*'
교대의 두 번째 부분만 살펴보았습니다. :<spaces><anything>
이는 다음 부분과 일치 하지만, 뒤따르는 부분뿐만 아니라 입력의 어느 곳에서나 해당 부분을 찾는다는 .zoo.<digits>
의미이기도 합니다 .:<spaces><anything>
.zoo.<digits>
그러나 이 문제를 해결하는 방법은 또 다른 PCRE 특수 연산자인 를 사용하는 것입니다 \G
. \G
주제의 시작 부분과 일치합니다. 단일 일치의 경우 이는 동일 ^
하지만 여러 일치의 경우( sed
/ perl
플래그를 생각해 보세요) 행에서 모든 일치 항목을 찾으려고 시도하는 것과 같으며 이전 일치가 끝난 후에도 일치합니다. 그렇다면 다음과 같이 하세요.g
s/.../.../g
-o
grep
grep -Po '\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
(?!^)
부정 예측 연산자는 어디에 있습니까?줄의 시작 부분에 있지 않음, \G
마지막으로 성공한(비어 있지 않은) 일치 이후에만 일치하므로 .*:\s+\K.*
마지막으로 성공한 일치 이후에만 일치하며, .foo.<digits>
교체의 다른 부분이 줄의 끝까지 일치하기 때문에 이 일치만 일치합니다.
다음과 같이 입력하면:
.zoo.1.zoo.2 tar: blah
그러면 다음이 출력됩니다:
1
2
blah
하지만. 이를 원하지 않는 경우 교대의 첫 번째 부분이 줄의 시작 부분에서만 일치하도록 할 수도 있습니다. 그것은 마치
grep -Po '^.*?\.zoo\.\K\d+|(?!^)\G.*:\s+\K.*'
또는 와 같은 입력에서는 여전히 출력됩니다 2
. 교체의 첫 번째 부분에서 미리보기 연산자를 사용하고 그 뒤에 공백이 아닌 하나 이상을 찾아 이 문제를 해결할 수 있습니다(문자가 아닌 문제를 방지하는 데에도 사용할 수 있음)..zoo.2 no colon character
.zoo.2 blah:
:<spaces>
$
grep -Po '^.*?\.zoo\.\K\d+(?=.*:\s+\S.*$)|(?!^)\G.*:\s+\K\S.*$'
sed
해당 정규식을 설명하려면 여러 페이지의 주석이 필요할 수 있으므로 여전히 직접 / 솔루션 을 사용하겠습니다 perl
.