Bagaimana cara menampilkan garis 2-4 setelah setiap hasil grep?

39

Saya mem-parsing file kotak surat yang menyimpan laporan server email untuk email yang gagal terkirim. Saya ingin mengekstrak alamat email yang salah, sehingga saya menghapusnya dari sistem. File log terlihat seperti ini:

...some content...
                   The mail system

<[email protected]>: 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

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

...some content...
                   The mail system

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

...etc.

Alamat surel datang 2 baris setelah satu baris dengan "Sistem surat". Menggunakan grep seperti ini memberi saya baris "Sistem surat" dan dua baris berikutnya:

grep -A 2 "The mail system" mbox_file

Namun, saya tidak tahu cara menghapus baris "Sistem surat" dan baris kosong kedua dari keluaran ini. Saya kira saya bisa menulis skrip PHP / Perl / Python untuk melakukannya, tapi saya ingin tahu apakah ini mungkin dengan grep atau alat standar lainnya. Saya mencoba memberikan offset negatif ke parameter -B:

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

Tapi grep mengeluh:

grep: -2: invalid context length argument

Apakah ada cara untuk melakukan ini dengan grep?

Milan Babuškov
sumber
3
-B menerima angka seperti -A akan, dan itu akan menampilkan baris sebelumnya sebelum pertandingan.
Nikhil Mulley
3
Ya, itu benar, tetapi Milan tidak tertarik pada apa yang mendahului pertandingan ... Masalah yang dia temui adalah -A dan -B hanya menerima nilai positif ... dan bahwa dalam kasus apa pun, -A dan -B dapat dapat digunakan relatif satu sama lain, seperti yang telah dia coba lakukan.
Peter.O
1
Hum, hanya untuk memastikan: itu adalah alamat dummy yang tidak Anda ekstrak (langsung) dari file yang Anda berikan, bukan?
Matthieu M.
1
@ Matthieu M. tidak, mereka dari file log nyata. Saya pikir karena mereka adalah alamat yang tidak valid, apa gunanya menemukan alamat palsu yang mungkin valid.
Milan Babuškov
stackoverflow.com/questions/8101701/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

29

Cara paling sederhana untuk menyelesaikannya grephanya menggunakan , adalah untuk pipa satu lagi terbalik grepdi akhir. Sebagai contoh:

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

Jika Anda tidak dikunci untuk menggunakan grep, coba sed...

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

Ketika ia menemukan baris yang berisi "Sistem surat", ia membaca baris berikutnya dua kali, melalui n;n;, membuang setiap baris sebelumnya saat melakukannya.
Ini meninggalkan baris ke-3 grup Anda dalam ruang pola, yang kemudian dicetak melalui pperintah sed . -nOpsi utama mencegah semua pencetakan lainnya.

Untuk mencetak dua baris berikutnya juga, itu hanya kasus berikutnya dan mencetak n;p dua kali lagi.

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

Baris berikutnya membaca untuk baris yang Anda butuhkan dapat diakumulasikan dan dicetak satu blok dengan hanya satu p... Nmembaca baris berikutnya dan menambahkannya ke ruang pola,

Ini adalah versi kental terakhir ...

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

Jika Anda ingin seperator kelompok , mirip dengan keluaran wouuld apa yang grep, Anda dapat menggunakan sed ini menyisipkan perintah i(yang harus perintah terakhir pada baris) ...

Berikut ini sintaks untuk menyertakan seperator grup

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

Ini adalah output untuk pertandingan pertama:

<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550
    Requested action not taken: mailbox unavailable (in reply to RCPT TO
    command)                                                                    
--
Peter.O
sumber
+1. Terima kasih. Saya tidak membutuhkannya dalam kasus ini, tetapi saya akan menyimpan bookmark ini kalau-kalau ada hal-hal yang lebih rumit untuk ditangani.
Milan Babuškov
Ini jawaban yang bagus!
dotancohen
9
grep -A 2 -B -2 "The mail system" mbox_file

-B untuk baris sebelumnya, jadi tidak perlu memberikan nilai -negatif.

grep -A 2 -B 2 "The mail system" mbox_file   # This will work please check
Mukesh Payghan
sumber
Ini tidak menjawab pertanyaan. -A 2 -B 2mencetak dari dua baris sebelum konteks menjadi 2 baris setelah konteks. Pertanyaannya adalah tentang mencetak dari 2 baris setelah konteks menjadi 4 baris setelah konteks.
daniel.neumann
1

Saya tidak melihat gunanya hanya menggunakan grep, kecuali jika itu merupakan kendala yang ketat. Itu tidak dapat dilakukan dengan satu panggilan ke grep.

grep -A 2 "The mail system" mbox_file | tail -n +3
  • grep: Temukan baris dan output 2 baris setelah,
  • tail: memotong 2 baris pertama (yaitu mulai dari baris ketiga).
TWiStErRob
sumber
2
Ini hanya berfungsi jika ada satu baris yang cocok, yang mungkin bukan pertanyaannya.
jw013
Bukan itu yang ditanyakan tetapi itu membantu saya dalam situasi saya sekarang :-).
daniel.neumann
1
@ daniel.neumann saya tahu, tapi saya benar-benar siap dan berpikir Google-fu orang lain juga akan memimpin di sini.
TWiStErRob
0

Ini mencetak 1 baris berikutnya setelah pertandingan regexp, menggunakan Perl

perl -ne 'print if( (/The mail system/ && ($end=1))..!$end-- )' 
noelbk
sumber