Ich analysiere eine Postfachdatei, in der E-Mail-Serverberichte für nicht erfolgreich zugestellte E-Mails gespeichert sind. Ich möchte also falsche E-Mail-Adressen extrahieren dass ich sie aus dem System entferne. Die Protokolldatei sieht folgendermaßen aus:
...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.
Die E-Mail-Adresse kommt 2 Zeilen nach einer Zeile mit „Das Mail-System“. Wenn ich grep wie dieses verwende, erhalte ich die Zeile „Das Mailsystem“ und die nächsten beiden Zeilen:
grep -A 2 "The mail system" mbox_file
Ich weiß jedoch nicht, wie ich das entfernen soll Zeile „Das Mailsystem“ und die zweite leere Zeile dieser Ausgabe. Ich denke, ich könnte dazu ein PHP / Perl / Python-Skript schreiben, aber ich frage mich, ob dies mit grep oder einem anderen Standardwerkzeug möglich ist. Ich habe versucht, dem Parameter -B einen negativen Offset zu geben:
grep -A 2 -B -2 "The mail system" mbox_file
Aber grep beschwert sich:
grep: -2: invalid context length argument
Gibt es eine Möglichkeit, dies mit grep zu tun?
Kommentare
- -B akzeptiert Zahlen wie -A und zeigt die an vorherige Zeilen vor dem Spiel.
- Ja, das ist wahr, aber Mailand ist ‚ nicht daran interessiert, was dem Spiel vorausgeht. Das Problem, auf das er gestoßen ist, ist, dass -A und -B nur positive Werte akzeptieren … und dass -A und -B in jedem Fall ‚ nicht relativ zueinander verwendet werden können , wie er es versucht hat.
- Hum, nur um sicherzugehen: Das sind Dummy-Adressen, die Sie nicht (direkt) aus der Datei extrahiert haben, die Sie erhalten haben, oder?
- @ Matthieu M. Nein, sie stammen aus einer echten Protokolldatei. Ich dachte mir, da es sich sowieso um ungültige Adressen handelt, was ‚ der Sinn ist, Dummy-Adressen zu erfinden, die möglicherweise gültig sind.
- stackoverflow.com/questions/8101701/…
Antwort
Der einfachste Weg, dies nur mit grep
zu lösen, besteht darin, am Ende ein weiteres invertiertes grep
weiterzuleiten . Zum Beispiel:
grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v "^\d*$"
Antwort
Wenn Sie nicht daran gebunden sind Versuchen Sie mit grep
sed
…
sed -n "/The mail system/{n;n;p}"
Wann Es findet eine Zeile mit „Das Mailsystem“ und liest die nächste Zeile zweimal über n;n;
, wobei jede vorherige Zeile verworfen wird.
Damit bleibt die dritte Zeile übrig Ihrer Gruppe im Musterbereich, der dann über den Befehl sed „s p
gedruckt wird. Die führende Option -n
verhindert jegliches andere Drucken .
Um auch die nächsten beiden Zeilen zu drucken, müssen Sie nur next und n;p
noch zweimal drucken.
sed -n "/The mail system/{n; n;p; n;p; n;p}"
Die Lesevorgänge in der nächsten Zeile für die von Ihnen benötigten Zeilen können mit nur einem p
… N
liest die nächste Zeile und hängt sie an den Musterraum an.
Hier ist die endgültige komprimierte Version …
sed -n "/The mail system/{n;n;N;N;p}"
Wenn Sie einen Gruppentrenner möchten, ähnlich dem, was grep ausgeben würde, können Sie den Befehl insert von sed verwenden i
(dies muss der letzte Befehl in einer Zeile sein) …
Hier ist die Syntax, um einen Gruppentrenner
sed -n "/The mail system/{n;n;N;N;p;i-- }" > output-file # or | ...
Hier ist die Ausgabe für die erste Übereinstimmung:
<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550 Requested action not taken: mailbox unavailable (in reply to RCPT TO command) --
Kommentare
- +1. Danke. Ich ‚ brauche es in diesem Fall nicht, aber ich ‚ Ich werde dieses Lesezeichen behalten, falls ich kompliziertere Dinge zu erledigen habe.
- Dies ist eine großartige Antwort!
Antwort
grep -A 2 -B -2 "The mail system" mbox_file
-B
gilt für vorherige Zeilen, daher muss kein negativer Wert angegeben werden.
grep -A 2 -B 2 "The mail system" mbox_file # This will work please check
Kommentare
- Dies beantwortet die Frage nicht.
-A 2 -B 2
druckt von zwei Zeilen vor dem Kontext bis zu zwei Zeilen nach dem Kontext. Bei der Frage geht es um das Drucken von 2 Zeilen nach dem Kontext auf 4 Zeilen nach dem Kontext.
Antwort
I. Es macht keinen Sinn, nur grep (s) zu verwenden, es sei denn, dies ist eine strenge Einschränkung. Dies kann nicht mit einem Aufruf von grep erfolgen.
grep -A 2 "The mail system" mbox_file | tail -n +3
- grep: Finde die Zeile und gib 2 Zeilen nach,
- tail: schneide die ersten 2 Zeilen ab (dh beginne mit der dritten Zeile).
Kommentare
- Dies funktioniert nur, wenn es eine einzige übereinstimmende Zeile gibt, was wahrscheinlich nicht das ist, was die Frage stellt.
- Das ist nichts, wonach die Frage gefragt hat, aber es hilft mir in meiner aktuellen Situation :-).
- @ daniel.neumann Ich weiß, aber ich war genau in Ihren Schuhen und dachte, andere ‚ Google-fu werden auch hier führen.
Antwort
Wenn Sie die ersten 2 Zeilen entfernen möchten, leiten Sie sie an
sed "1,2d"
wie in
grep -A 2 "The mail system" mbox_file | sed "1,2d"
Kommentare
- Sie haben die Tatsache übersehen, dass das Muster häufig vorkommt. Wenn in den Zeilen 4, 14, 24, 34,… „Das Mailsystem“ angezeigt wird, möchte das OP die Zeilen 6, 16, 26, 36,… sehen. Ihre Antwort lautet 6, 14-16, 24-26, 34- 36,….
Antwort
Hiermit wird die nächste Zeile nach dem regulären Ausdruck mit Perl
perl -ne "print if( (/The mail system/ && ($end=1))..!$end-- )"