Як відображати рядки 2-4 після кожного результату грепінгу?


39

Я аналізую файл поштової скриньки, який зберігає звіти сервера електронної пошти для невдало доставленої електронної пошти. Я хочу витягнути погані адреси електронної пошти, щоб видалити їх із системи. Файл журналу виглядає так:

...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 -A 2 "The mail system" mbox_file

Однак я не знаю, як видалити рядок "Поштова система" та другий порожній рядок із цього виводу. Я думаю, я міг би написати сценарій PHP / Perl / Python, щоб це зробити, але мені цікаво, чи можливо це за допомогою grep чи іншого стандартного інструменту. Я намагався надати негативне зміщення параметру -B:

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

Але греп скаржиться:

grep: -2: invalid context length argument

Чи є спосіб зробити це з грепом?


3
-B приймає цифру як -A, і вона відображатиме попередні рядки перед матчем.
Nikhil Mulley

3
Так, це правда, але Мілану не цікаво, що передує матчу ... Проблема, з якою він зіткнувся, полягає в тому, що -A і -B приймають лише позитивні значення ... і що у будь-якому випадку, -A і -B можуть не можна використовувати відносно один одного, як це робив він.
Пітер.О

1
Гум, просто щоб переконатися: це фіктивні адреси, які ви (безпосередньо) не витягнули з файлу, який вам дали, правда?
Матьє М.

1
@Matthieu M. ні, вони зі справжнього файлу журналу. Я зрозумів, оскільки вони все-таки є недійсними адресами, який сенс вигадувати фіктивні адреси, які можуть бути дійсними.
Мілан Бабушків

Відповіді:


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}'   

Зчитування наступного рядка для потрібних рядків може бути накопичено і надруковано в одному блоці лише одним 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. Спасибі. Мені це не потрібно в цьому випадку, але я буду зберігати цю закладку, якщо я отримаю складніші речі.
Мілан Бабушков

Це чудова відповідь!
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 рядків після контексту. Питання стосується друку від 2 рядків після контексту до 4 рядків після контексту.
daniel.neumann

1

Я не бачу сенсу використовувати лише grep (и), за винятком випадків, коли це суворе обмеження. Це неможливо зробити одним закликом виступити.

grep -A 2 "The mail system" mbox_file | tail -n +3
  • grep: Знайдіть рядок і виведіть два рядки після,
  • хвіст: обріжте перші 2 лінії (тобто почніть з третього рядка).

2
Це працює лише в тому випадку, якщо є одна відповідна лінія, імовірно, це не те, що задається питанням.
jw013

Це питання не про що, але це допомагає мені в моїй ситуації :-).
daniel.neumann

1
@ daniel.neumann Я знаю, але я точно знаходився у вашому взутті і думав, що і сюди приведе чужий Google-фу.
TWiStErRob

0

Це друкує наступний 1 рядок після збігу повторної передачі, використовуючи Perl

perl -ne 'print if( (/The mail system/ && ($end=1))..!$end-- )' 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.