각 grep 결과 후에 라인 2-4를 표시하는 방법은 무엇입니까?


40

성공적으로 배달되지 않은 전자 메일에 대한 전자 메일 서버 보고서를 저장하는 사서함 파일을 구문 분석하고 있습니다. 잘못된 전자 메일 주소를 추출하여 시스템에서 제거하려고합니다. 로그 파일은 다음과 같습니다.

...some content...
                   The mail system

<slavicatomic118@hotmail.com>: host mx1.hotmail.com[65.54.188.94] said: 550
    Requested action not taken: mailbox unavailable (in reply to RCPT TO
    command)

...some content...
                   The mail system

<oki88@optimumpro.net>: host viking.optimumpro.net[79.101.51.82] said: 550
    Unknown user (in reply to RCPT TO command)

...some content...
                   The mail system

<sigirna_luka@yahoo.com>: host mta5.am0.yahoodns.net[74.6.140.64] said: 554
    delivery error: dd This user doesn't have a yahoo.com account
    (sigirna_luka@yahoo.com) [0] - mta1172.mail.sk1.yahoo.com (in reply to end
    of DATA command)

...etc.

이메일 주소는 "메일 시스템"으로 한 줄 뒤에 2 줄이됩니다. 이와 같이 grep을 사용하면 "메일 시스템"줄과 다음 두 줄이 나옵니다.

grep -A 2 "The mail system" mbox_file

그러나이 출력에서 ​​"메일 시스템"줄과 두 번째 빈 줄을 제거하는 방법을 모르겠습니다. PHP / Perl / Python 스크립트를 작성하여 작성할 수 있다고 생각하지만 grep 또는 다른 표준 도구로 이것이 가능한지 궁금합니다. -B 매개 변수에 음수 오프셋을 주려고했습니다.

grep -A 2 -B -2 "The mail system" mbox_file

그러나 grep은 불평합니다.

grep: -2: invalid context length argument

grep으로 이것을 할 수있는 방법이 있습니까?


3
-B는 -A처럼 숫자를 받아들이고 일치하기 전에 이전 줄을 표시합니다.
Nikhil Mulley 2012

3
네, 맞습니다. 그러나 밀라노 는 경기 전의 것에 관심이 없습니다 ... 그가 직면 한 문제는 -A와 -B는 양수 값만 받아들이고, 어떤 경우에도 -A와 -B는 그가 시도한 것처럼 서로에 대해 사용하지 마십시오.
Peter.O

1
흠, 그냥 확인하십시오 : 그것들은 당신이 주어진 파일에서 (직접적으로) 추출하지 않은 더미 주소입니다.
Matthieu M.

1
@Matthieu M. 아니요, 실제 로그 파일에서 가져 왔습니다. 어쨌든 유효하지 않은 더미 주소를 발명하는 요점은 유효하지 않은 주소이기 때문입니다.
Milan Babuškov

답변:


29

grep단지 그것을 사용하여 그것을 해결하는 가장 간단한 방법 grep은 끝에 하나 더 거꾸로 파이프하는 것 입니다. 예를 들면 다음과 같습니다.

grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v '^\d*$'

28

를 사용하지 않으려면 다음을 grep시도하십시오 sed...

sed -n '/The mail system/{n;n;p}' 

"메일 시스템"을 포함하는 행을 찾으면을 통해 다음 행을 두 번 읽고 n;n;이전의 각 행을 버립니다.
그러면 그룹의 세 번째 줄이 패턴 공간에 남게되고 sed의 p명령을 통해 -n인쇄됩니다. 선행 옵션은 다른 모든 인쇄를 방지합니다.

다음 두 줄도 인쇄하려면 다음과 같이 n;p 두 번 더 인쇄하십시오 .

sed -n '/The mail system/{n; n;p; n;p; n;p}'   

다음 줄은 축적 된 단 하나 AA 단일 블록을 인쇄 할 수 있습니다 필요한 라인에 대해 읽고 p... N, 다음 라인을 읽고 그 패턴 공간에 추가합니다

최종 요약 버전은 다음과 같습니다.

sed -n '/The mail system/{n;n;N;N;p}'   

grep wouuld 출력과 비슷한 그룹 seperator 를 원한다면 sed의 insert 명령을 사용할 수 있습니다 i(행의 마지막 명령이어야 함) ...

다음은 그룹 구분 기호 를 포함하는 구문입니다.

sed -n '/The mail system/{n;n;N;N;p;i--
       }' > output-file  # or | ...

첫 번째 일치 결과는 다음과 같습니다.

<slavicatomic118@hotmail.com>: host mx1.hotmail.com[65.54.188.94] said: 550
    Requested action not taken: mailbox unavailable (in reply to RCPT TO
    command)                                                                    
--

+1. 감사. 이 경우에는 필요하지 않지만 처리하기가 더 복잡한 경우에 대비하여이 책갈피를 유지합니다.
밀라노 Babuškov

이것은 좋은 답변입니다!
dotancohen

9
grep -A 2 -B -2 "The mail system" mbox_file

-B 이전 줄에 대한 것이므로 음수 값을 제공 할 필요가 없습니다.

grep -A 2 -B 2 "The mail system" mbox_file   # This will work please check

이것은 질문에 대답하지 않습니다. -A 2 -B 2컨텍스트 앞의 두 줄에서 컨텍스트 후 두 줄로 인쇄합니다. 문제는 컨텍스트 후 2 줄에서 컨텍스트 후 4 줄로 인쇄하는 것입니다.
daniel.neumann

1

엄격한 제약 조건을 제외하고는 grep 만 사용하는 것이 중요하지 않습니다. 한 번의 grep 호출로 수행 할 수 없습니다.

grep -A 2 "The mail system" mbox_file | tail -n +3
  • grep : 라인을 찾아서 2 라인을 출력 한 후
  • 꼬리 : 처음 두 줄을 자릅니다 (즉, 세 번째 줄에서 시작).

2
이것은 일치하는 단일 줄이있는 경우에만 작동하며 아마도 질문이 아닌 것입니다.
jw013

그것은 질문이 요구 한 것은 아니지만 내 현재 상황에서 도움이됩니다 :-).
daniel.neumann

1
@ daniel.neumann 알고 있지만, 나는 정확히 당신의 신발에 있었고 다른 사람들의 Google-fu도 여기에서 이끌 것이라고 생각했습니다.
TWiStErRob

0

이것은 Perl을 사용하여 정규 표현식 일치 다음 줄을 인쇄합니다.

perl -ne 'print if( (/The mail system/ && ($end=1))..!$end-- )' 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.