Parsuję plik skrzynki pocztowej, który przechowuje raporty serwera poczty e-mail pod kątem nieudanej dostawy wiadomości e-mail. Chcę wyodrębnić złe adresy e-mail, więc że usunę je z systemu. Plik dziennika wygląda następująco:
...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.
Adres e-mail występuje w dwóch wierszach po wierszu z wyrażeniem „System pocztowy” . Użycie grepa w ten sposób daje mi wiersz „System pocztowy” i następne dwa wiersze:
grep -A 2 "The mail system" mbox_file
Jednak nie wiem, jak usunąć Wiersz „systemu pocztowego” i drugi pusty wiersz tego wyjścia. Myślę, że mógłbym napisać skrypt PHP / Perl / Python, aby to zrobić, ale zastanawiam się, czy jest to możliwe za pomocą grepa lub innego standardowego narzędzia. Próbowałem podać ujemne przesunięcie dla parametru -B:
grep -A 2 -B -2 "The mail system" mbox_file
Ale grep narzeka:
grep: -2: invalid context length argument
Czy istnieje sposób na zrobienie tego za pomocą grepa?
Komentarze
- -B akceptuje liczby w taki sam sposób, jak -A i wyświetli poprzednie wiersze przed meczem.
- Tak, to prawda, ale Mediolan nie ' nie interesuje się tym, co poprzedza mecz. . Problem, który napotkał polega na tym, że -A i -B akceptują tylko wartości dodatnie … i że w każdym przypadku -A i -B mogą ' t być używane względem siebie , tak jak próbował.
- Hum, tylko dla pewności: to są fikcyjne adresy, których nie wyodrębniłeś (bezpośrednio) z otrzymanego pliku, prawda?
- @Matthieu M. nie, pochodzą z prawdziwego pliku dziennika. Pomyślałem, że skoro i tak są to nieprawidłowe adresy, co ' jest celem wymyślania fałszywych adresów, które mogą być prawidłowe.
- stackoverflow.com/questions/8101701/…
Odpowiedź
Najprostszym sposobem rozwiązania tego problemu przy użyciu tylko grep
jest wyprowadzenie na końcu jeszcze jednego odwróconego grep
. Na przykład:
grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v "^\d*$"
Answer
Jeśli nie jesteś zablokowany używając grep
, spróbuj sed
…
sed -n "/The mail system/{n;n;p}"
Kiedy znajduje wiersz zawierający „The mail system”, dwukrotnie czyta następny wiersz, poprzez n;n;
, pomijając przy tym każdą poprzednią linię.
To pozostawia trzeci wiersz Twojej grupy w przestrzeni wzorca, która jest następnie drukowana za pomocą polecenia sed „s p
. Początkowa opcja -n
zapobiega wszelkim innym drukom .
Aby wydrukować również następne dwa wiersze, wystarczy wpisać następny i wypisać n;p
jeszcze dwa razy.
sed -n "/The mail system/{n; n;p; n;p; n;p}"
Odczyty w następnym wierszu żądanych wierszy można gromadzić i drukować jako pojedynczy blok z tylko jednym p
… N
czyta następną linię i dołącza ją do przestrzeni wzorców,
Oto ostateczna, skondensowana wersja …
sed -n "/The mail system/{n;n;N;N;p}"
Jeśli potrzebujesz separatora grup , podobnego do tego, co wyprowadził grep, możesz użyć polecenia sed „s wstaw i
(które musi być ostatnim poleceniem w wierszu) …
Oto składnia dołączania separatora grup
sed -n "/The mail system/{n;n;N;N;p;i-- }" > output-file # or | ...
Oto dane wyjściowe dla pierwszego dopasowania:
<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550 Requested action not taken: mailbox unavailable (in reply to RCPT TO command) --
Komentarze
- +1. Dziękuję. Nie ' nie potrzebuję tego w tym przypadku, ale ' Zachowam tę zakładkę na wypadek, gdybym potrzebował bardziej skomplikowanych rzeczy.
- To świetna odpowiedź!
Odpowiedź
grep -A 2 -B -2 "The mail system" mbox_file
-B
dotyczy poprzednich wierszy, więc nie ma potrzeby podawania -negatywnej wartości.
grep -A 2 -B 2 "The mail system" mbox_file # This will work please check
Komentarze
- To nie odpowiada na pytanie.
-A 2 -B 2
drukuje od dwóch wierszy przed kontekstem do dwóch wierszy po kontekście. Pytanie dotyczy drukowania od 2 linii po kontekście do 4 linii po kontekście.
Odpowiedź
I nie widzę sensu w używaniu tylko grep (s), chyba że jest to „ścisłe ograniczenie. Nie można tego zrobić za pomocą jednego wywołania grepa”.
grep -A 2 "The mail system" mbox_file | tail -n +3
- grep: znajdź linię i wyprowadź 2 wiersze po,
- tail: wytnij pierwsze 2 wiersze (tj. zacznij od trzeciego wiersza).
Komentarze
- Działa to tylko wtedy, gdy istnieje jedna pasująca linia, co prawdopodobnie nie jest tym, o co chodzi w pytaniu.
- To nie jest to, o co pytano, ale to pomaga mi w mojej obecnej sytuacji :-).
- @ daniel.neumann Wiem, ale byłem dokładnie na twoim miejscu i myślałem, że inni ' Google-fu tu też prowadzić.
Odpowiedź
Jeśli chcesz usunąć pierwsze 2 wiersze, przeprowadź wyprowadzenie do sed
sed "1,2d"
jak w
grep -A 2 "The mail system" mbox_file | sed "1,2d"
Komentarze
- Przegapiłeś fakt, że wzorzec występuje wiele razy. Jeśli „System poczty” pojawia się w wierszach 4, 14, 24, 34,…, PO chce zobaczyć wiersze 6, 16, 26, 36,… Twoja odpowiedź da 6, 14-16, 24-26, 34- 36,….
Odpowiedź
Drukuje następną 1 linię po dopasowaniu wyrażenia regularnego, używając Perla
perl -ne "print if( (/The mail system/ && ($end=1))..!$end-- )"