จะแสดงบรรทัด 2-4 หลังจากผลลัพธ์ grep แต่ละรายการอย่างไร


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

3
ใช่นั่นเป็นความจริง แต่มิลานไม่สนใจสิ่งที่นำหน้าการแข่งขัน ... ปัญหาที่เขาพบคือ - และ -B ยอมรับเฉพาะค่าบวกเท่านั้น ... และในกรณีใด ๆ -A และ -B สามารถ ไม่ต้องใช้ความสัมพันธ์ซึ่งกันและกันขณะที่เขาพยายามทำ
Peter.O

1
ครวญครางเพียงเพื่อให้แน่ใจว่า: ที่อยู่หลอกตาที่คุณไม่ได้ (โดยตรง) แยกจากไฟล์ที่คุณได้รับใช่ไหม?
Matthieu M.

1
@Matthieu M. no พวกเขามาจากไฟล์บันทึกจริง ฉันคิดว่าเนื่องจากพวกเขาเป็นที่อยู่ที่ไม่ถูกต้องอยู่แล้วจุดของการประดิษฐ์ที่อยู่จำลองที่อาจใช้ได้คืออะไร
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;ยกเลิกแต่ละบรรทัดก่อนหน้าตามที่ทำ
การทำเช่นนี้จะทำให้บรรทัดที่ 3 ของกลุ่มคุณอยู่ในพื้นที่รูปแบบซึ่งจะถูกพิมพ์ผ่านpคำสั่งของ sed -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 คุณสามารถใช้คำสั่งแทรกของ sed 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 ขอบคุณ ฉันไม่ต้องการมันในกรณีนี้ แต่ฉันจะเก็บบุ๊กมาร์กนี้ไว้ในกรณีที่ฉันได้รับข้อมูลที่ซับซ้อนมากขึ้น
Milan Babuškov

นี่เป็นคำตอบที่ยอดเยี่ยม!
dotancohen

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

-B สำหรับบรรทัดก่อนหน้าดังนั้นไม่จำเป็นต้องให้ค่า -negative

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

นี่ไม่ได้ตอบคำถาม -A 2 -B 2พิมพ์จากสองบรรทัดก่อนบริบทเป็น 2 บรรทัดหลังบริบท คำถามคือเกี่ยวกับการพิมพ์จาก 2 บรรทัดหลังจากบริบทถึง 4 บรรทัดหลังจากบริบท
daniel.neumann

1

ฉันไม่เห็นจุดที่ใช้ grep (s) เพียงอย่างเดียวยกเว้นว่าเป็นข้อ จำกัด ที่เข้มงวด ไม่สามารถทำการเรียก grep ได้เพียงครั้งเดียว

grep -A 2 "The mail system" mbox_file | tail -n +3
  • grep: ค้นหาบรรทัดและผลลัพธ์ 2 บรรทัดหลัง
  • tail: ตัด 2 บรรทัดแรก (เช่นเริ่มจากบรรทัดที่สาม)

2
ใช้งานได้เฉพาะในกรณีที่มีการจับคู่บรรทัดเดียวซึ่งอาจไม่ใช่คำถามที่ถาม
jw013

นั่นคือสิ่งที่คำถามถาม แต่มันช่วยฉันในสถานการณ์ปัจจุบันของฉัน :-)
daniel.neumann

1
@ daniel.neumann ฉันรู้ แต่ฉันอยู่ในรองเท้าของคุณและคิดว่า Google-fu ของคนอื่นจะเป็นผู้นำที่นี่เช่นกัน
TWiStErRob

0

นี่จะพิมพ์ 1 บรรทัดถัดไปหลังจากการจับคู่ regexp โดยใช้ Perl

perl -ne 'print if( (/The mail system/ && ($end=1))..!$end-- )' 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.