grep
/ egrep
를 오용하는 것 같습니다.
여러 줄의 문자열을 검색하려고했지만 찾고있는 항목이 일치해야한다는 것을 알고있는 동안 일치 항목을 찾을 수 없었습니다. 원래는 내 정규식이 잘못되었다고 생각했지만 결국에는 도구는 한 줄로 작동합니다 (또한 내 정규식이 너무 사소해서 문제가 될 수 없습니다).
그러면 여러 줄에서 패턴을 검색하는 데 어떤 도구를 사용할까요?
댓글
답변
다음은 여러 줄에 걸쳐 grep
와 유사한 동작을 제공하는 sed
입니다.
sed -n "/foo/{:start /bar/!{N;b start};/your_regex/p}" your_file
작동 방식
-
-n
는 모든 행을 인쇄하는 기본 동작을 억제합니다. -
/foo/{}
는foo
와 일치하는 줄에 구불 구불 한 부분을 수행합니다.foo
를 패턴의 시작 부분으로 바꿉니다. -
:start
는 정규식의 끝을 찾을 때까지 루프를 계속하는 데 도움이되는 분기 레이블입니다. -
/bar/!{}
는 squigglies에있는 항목을 실행합니다.bar
와 일치하지 않는 줄. 패턴의 끝 부분을 포함합니다. -
N
는 활성 버퍼에 다음 줄을 추가합니다 (sed
는 이것을 패턴 공간이라고합니다.) -
b start
는 우리가 만든start
라벨로 무조건 분기됩니다. 패턴 공간에bar
가 포함되지 않는 한 다음 줄을 계속 추가하기 위해 더 일찍. -
/your_regex/p
는your_regex
와 일치하는 경우 패턴 공간을 인쇄합니다.your_regex
를 여러 줄에 걸쳐 일치시키려는 전체 표현식으로 바꿔야합니다.
댓글
- +1 이것을 toolikt에 추가하십시오! 감사합니다.
- 참고 : MacOS에서는
sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
-
sed: unterminated {
오류 발생 - @Nomaed Shot in the dark here하지만 정규식에 ” {” 문자가 포함되어 있습니까? 그렇다면 ‘ 백 슬래시 이스케이프 처리해야합니다.
- @Nomaed
sed
구현 간의 차이점 위의 스크립트를 표준 규격으로 만들기 위해 해당 답변의 권장 사항을 따르려고했지만 ” start “가 정의되지 않았다고 말했습니다. 상표. 따라서 ‘이 작업이 표준 준수 방식으로 수행 될 수 있는지 확실하지 않습니다. 관리하는 경우 내 답변을 자유롭게 수정하십시오.
li>
답변
일반적으로 도구를 사용합니다. pcregrep
라고하며 yum
또는 apt
를 사용하여 대부분의 Linux 버전에 설치할 수 있습니다.
예 :
콘텐츠가있는 testfile
라는 파일이 있다고 가정합니다.
abc blah blah blah def blah blah blah
다음 명령을 실행할 수 있습니다.
$ pcregrep -M "abc.*(\n|.)*def" testfile
여러 줄에서 패턴 일치를 수행합니다.
또한, sed
에서도 동일한 작업을 수행 할 수 있습니다.
$ sed -e "/abc/,/def/!d" testfile
댓글
- 이
sed
제안 건너 뛰기def
가있는 줄
답변
간단히 Perl-regexp
매개 변수 P
를 지원하는 일반 grep이이 작업을 수행합니다.
$ echo "abc blah blah blah def blah blah blah" | grep -oPz "(?s)abc.*?def" abc blah blah blah def
(?s)
DOTALL 수정자를 호출하여 정규식에서 점을 만들어 문자뿐만 아니라 줄 바꿈도 일치시킵니다.
댓글
- 이 솔루션을 시도해도 출력이 ‘ def
그러나 파일의 끝으로 이동 ‘ blah ‘
- 아마도 귀하의 grep은
-P
옵션을 지원하지 않습니다. - 이것은 저에게 유일한 방법이었습니다. 모든
sed
제안을 시도했습니다. 하지만 ‘ grep 대안을 설치하는 데까지 이르지 않았습니다. -
$ grep --version
:grep (GNU grep) 3.1
Windows Git Bash 에는-P, --perl-regexp
옵션이 있지만(?s)
에는 옵션이 없습니다 ‘가 작동하지 않는 것 같습니다. 여전히 첫 번째 줄만 표시됩니다. 동일한 테스트 문자열을 가진 동일한 패턴이 regex101.com 에서 작동합니다. Git Bash에 대안이 있습니까?sed
? (sed (GNU sed) 4.8
여기) - 컨텍스트 를 출력에 추가하는 방법을 알고 있습니까? grep -1은 ‘ 여기서 작동하지 않습니다.
답변
“Perl을 사용한보다 간단한 접근 방식 :
perl -e "$f=join("",<>); print $& if $f=~/foo\nbar.*\n/m" file
또는 (JosephR 이 sed
경로 , 뻔뻔하게 그의 제안 을 훔칩니다.
perl -n000e "print $& while /^foo.*\nbar.*\n/mg" file
### Explanation
$f=join("",<>);
: 전체 파일을 읽고 내용 (줄 바꿈 및 전체)을 변수
. 그런 다음 foo\nbar.*\n
일치를 시도하고 일치하면 인쇄합니다 (특수 변수 $&
는 발견 된 마지막 일치 항목을 보유합니다). ///m
는 줄 바꿈에서 정규식을 일치시키는 데 필요합니다.
-0
는 입력 레코드 구분자를 설정합니다. 이것을 00
로 설정하면 Perl이 연속적인 줄 바꿈 (\n\n
)을 레코드 구분자로 사용하는 “단락 모드”가 활성화됩니다. 연속 된 줄 바꿈이없는 경우 전체 파일을 한 번에 읽습니다 (슬러 핑).
### 경고 : 대용량 파일에 대해이 작업을 수행하지 마세요 . 전체 파일을 메모리에 저장하면 문제가 될 수 있습니다.
댓글
- 나는 ‘ Perl에 대해 많이 알고 있지만 ‘ 엄격히 말하자면
my $f=join("",<>);
일 필요는 없습니까? - @Sapphire_Brick 전용 엄격 모드 (
use strict;
) 인 경우. 특히 더 큰 스크립트를 작성할 때 ‘ 좋은 습관이지만, 이와 같이 작은 한 줄짜리에서는 ‘ 과도하게 사용됩니다. 하나.
답변
파일이 있다고 가정합니다. test.txt 포함 :
blabla blabla foo here is the text to keep between the 2 patterns bar blabla blabla
다음 코드를 사용할 수 있습니다.
sed -n "/foo/,/bar/p" test.txt
다음 출력의 경우 :
foo here is the text to keep between the 2 patterns bar
답변
grep 대안 sift 는 여러 줄 일치를 지원합니다 (면책 조항 : 저자입니다).
testfile
포함 :
<book> <title>Lorem Ipsum</title> <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</description> </book>
sift -m '<description>.*?</description>'
( 설명)
결과 :
testfile: <description>Lorem ipsum dolor sit amet, consectetur testfile: adipiscing elit, sed do eiusmod tempor incididunt ut testfile: labore et dolore magna aliqua</description>
sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename
(추출 및 설명 형식 변경)
결과 :
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
댓글
- 아주 멋진 도구입니다. 축하합니다! Ubuntu와 같은 배포판에 포함 해보십시오.
Answer
저는 grep을 사용하여이 문제를 해결했습니다. 다른 grep이있는 옵션.
grep first_line_word -A 1 testfile | grep second_line_word
-A 1 옵션은 찾은 줄 뒤에 한 줄을 인쇄합니다. 물론 파일과 단어 조합에 따라 다릅니다. 하지만 저에게는 가장 빠르고 안정적인 솔루션이었습니다.
댓글
- alias grepp = ‘ grep –color = auto -B10 -A20 -i ‘ 그런 다음 cat somefile | grepp blah | grepp foo | grepp bar … 네 -A와 -B는 매우 편리합니다 …가장 좋은 답변이 있습니다.
- 이는 ‘ 초 결정적이지 않으며 다른 단일 라인을 얻기 위해 전체 패턴을 무시합니다. 첫 번째 줄에). ‘ 당신이 원하는 패턴에 도달하기 위해 필요한만큼 멀리 가도록 프로그램에 지시하는 것이 좋습니다. ‘ 일치시키려는 텍스트의 끝이 ‘ 확실합니다. 예를 들어
testfile
가 업데이트되어second_line_word
가 세 번째 줄에있는 경우 이제 첫 번째 줄이 누락 된 것이 아닙니다. 두 번째grep
)이지만 ‘ 둘 사이에 나타나기 시작한 줄이 누락되지 않았습니다. - 이 이미 이해 한 출력에 한 줄만 표시하려는 ad hoc 명령에는 충분한 MO가 될 것입니다. 나는 ‘ ‘가 OP가 추구하는 것이라고 생각하지 않으며 아마도 그 시점에서 복사 / 붙여 넣기를 할 수도 있습니다. 임시적입니다.
답변
이 작업을 수행하는 한 가지 방법은 Perl을 사용하는 것입니다. 예 : 다음은 foo
라는 파일의 내용입니다.
foo line 1 bar line 2 foo foo foo line 5 foo bar line 6
자, 여기에 Perl이 있습니다. foo로 시작하고 다음에 bar로 시작하는 모든 줄과 일치 :
cat foo | perl -e "while(<>){$all .= $_} while($all =~ /^(foo[^\n]*\nbar[^\n]*\n)/m) { print $1; $all =~ s/^(foo[^\n]*\nbar[^\n]*\n)//m; }"
Perl, 세분화 :
-
while(<>){$all .= $_}
전체 표준 입력을 변수$all
- 변수
all
에는 정규식이 있습니다 … -
/^(foo[^\n]*\nbar[^\n]*\n)/m
정규식 : foo 줄의 시작 부분에 줄 바꿈이 아닌 문자, 줄 바꿈, 바로 “bar”, 그리고 줄이있는 나머지 줄. 정규식 끝에있는/m
는 “여러 줄에서 일치”를 의미합니다. -
print $1
정규식의 일부를 인쇄합니다. 괄호 안에있는 (이 경우 전체 정규식) -
s/^(foo[^\n]*\nbar[^\n]*\n)//m
정규식에 대한 첫 번째 일치 항목을 삭제하여 정규식의 여러 대소 문자를 일치시킬 수 있습니다. 문제의 파일
및 출력 :
foo line 1 bar line 2 foo bar line 6
댓글
- Perl을 좀 더 관용적으로 줄일 수 있다는 점을 알려드립니다.
perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo
답변
자신을 제외한 두 패턴 사이의 텍스트를 얻으려면
test.txt 포함 :
blabla blabla foo here is the text to keep between the 2 patterns bar blabla blabla
다음 코드를 사용할 수 있습니다.
sed -n "/foo/{ n b gotoloop :loop N :gotoloop /bar/!{ h b loop } /bar/{ g p } }" test.txt
다음 출력의 경우 :
here is the text to keep between the 2 patterns
어떻게 작동합니까? 단계별로 만들기
-
/foo/{
는 줄에 “foo”가 포함되어있을 때 트리거됩니다. -
n
패턴 공간을 다음 줄로 바꿉니다. 즉, “here”라는 단어가 “gotoloop”레이블로 분기됩니다. -
b gotoloop
>:gotoloop
는 “gotoloop”레이블을 정의합니다. -
/bar/!{
패턴에 “bar”가 포함되지 않은 경우 -
h
보류 공간을 패턴으로 바꾸면 “여기”가 보류 공간에 저장됩니다. -
b loop
“루프”레이블에 대한 분기 -
:loop
는 “루프”레이블을 정의합니다. -
N
패턴을 보류 공간에 추가합니다.
이제 보류 공간에 다음이 포함됩니다.
“here”
“is the” -
:gotoloop
이제 4 단계에 있습니다. 줄에 “bar”가 포함될 때까지 반복합니다. -
/bar/
루프가 완료되고 “bar”가 발견되었습니다. s 패턴 공간 - 패턴 공간은 기본 루프 중에 저장 한”foo “와”bar “사이의 모든 행을 포함하는 보류 공간으로 대체됩니다.
-
p
패턴 공간을 표준 출력으로 복사
완료!
댓글
- 잘하셨습니다. +1. 저는 일반적으로 이러한 명령을 tr ‘ SOH로 줄 바꿈하고 일반 sed 명령을 수행 한 다음 줄 바꿈을 바꾸는 방식으로 사용하지 않습니다.
grep
로이 작업을 수행하는 방법을 묻는 동안. 밀접하게 관련되어 있지만 IMO는 아닙니다."grep"
가 동사 “를 grep에 “로 제안하고 상위 답변이라고 말했습니다. 허용되는 경우를 포함하여 ‘ grep을 사용하지 마십시오.