Jag analyserar en brevlådefil som lagrar e-postserverrapporter för misslyckad levererad e-post. Jag vill extrahera dåliga e-postadresser, så att jag tar bort dem från systemet. Loggfilen ser ut så här:
...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.
E-postadressen kommer två rader efter en rad med ”The mail system” Att använda grep så här ger mig raden ”The mail system” och de två följande raderna:
grep -A 2 "The mail system" mbox_file
Jag vet dock inte hur jag tar bort Raden ”E-postsystemet” och den andra tomma raden från denna utgång. Jag antar att jag kunde skriva PHP / Perl / Python-skript för att göra det, men jag undrar om detta är möjligt med grep eller något annat standardverktyg. Jag försökte ge negativ förskjutning till -B-parametern:
grep -A 2 -B -2 "The mail system" mbox_file
Men grep klagar:
grep: -2: invalid context length argument
Finns det ett sätt att göra detta med grep?
Kommentarer
- -B accepterar siffror som -A skulle, och det skulle visa föregående rader före matchen.
- Ja, det stämmer, men Milan är inte ' t intresserad av vad som föregår matchen .. Problemet som han stötte på är att -A och -B endast accepterar positiva värden … och att i alla fall -A och -B kan ' inte användas i förhållande till varandra , som han har försökt göra.
- Hum, bara för att se till: det är dummyadresser som du inte (direkt) extraherade från filen du fick, eller hur?
- @Matthieu M. nej, de kommer från riktig loggfil. Jag tänkte att eftersom de är ogiltiga adresser ändå, vad ' är poängen med att uppfinna dummy-adresser som kan vara giltiga.
- stackoverflow.com/questions/8101701/…
Svar
Det enklaste sättet att lösa det med grep
är att pipa ytterligare en inverterad grep
i slutet . Till exempel:
grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v "^\d*$"
Svar
Om du inte är låst till med grep
, prova sed
…
sed -n "/The mail system/{n;n;p}"
När den hittar en rad som innehåller ”E-postsystemet”, den läser nästa rad två gånger, via n;n;
, och kasserar varje föregående rad när den gör det.
Detta lämnar den tredje raden för din grupp i mönsterutrymmet, som sedan skrivs ut via sed ”s p
-kommandot .. Det ledande -n
-alternativet förhindrar all annan utskrift .
För att också skriva ut de två följande raderna är det bara nästa och skriv ut n;p
två gånger till.
sed -n "/The mail system/{n; n;p; n;p; n;p}"
Nästa rad som läses för de rader du behöver kan ackumuleras och skrivas ut ett enda block med bara en p
… N
läser nästa rad och lägger till den i mönsterutrymmet,
Här är den slutliga sammanfattade versionen …
sed -n "/The mail system/{n;n;N;N;p}"
Om du vill ha en gruppseparator , liknande vad grep vill mata ut, kan du använda kommandot sed ”s infoga i
(vilket måste vara det sista kommandot på en rad) …
Här är syntaxen för att inkludera en gruppseparator
sed -n "/The mail system/{n;n;N;N;p;i-- }" > output-file # or | ...
Här är utgången för den första matchningen:
<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550 Requested action not taken: mailbox unavailable (in reply to RCPT TO command) --
Kommentarer
- +1. Tack. Jag behöver inte ' i det här fallet, men jag ' kommer att behålla det här bokmärket om jag får mer komplicerade saker att hantera.
- Det här är ett bra svar!
Svar
grep -A 2 -B -2 "The mail system" mbox_file
-B
är för tidigare rader, så inget behov av att ge -negativt värde.
grep -A 2 -B 2 "The mail system" mbox_file # This will work please check
Kommentarer
- Detta svarar inte på frågan.
-A 2 -B 2
skrivs ut från två rader före sammanhanget till två rader efter sammanhanget. Frågan handlar om att skriva ut från 2 rader efter kontext till 4 rader efter kontext.
Svar
I ser ingen mening med att bara använda grep (er), förutom om det är en strikt begränsning. Det kan inte göras med ett samtal till grep.
grep -A 2 "The mail system" mbox_file | tail -n +3
- grep: Hitta raden och mata ut två rader efter,
- svans: klipp de två första raderna (dvs. börja från tredje raden).
Kommentarer
- Detta fungerar bara om det finns en enda matchande rad, vilket förmodligen inte är vad frågan ställer.
- Det är ingenting vad frågan ställde efter men den hjälper mig i min nuvarande situation :-).
- @ daniel.neumann Jag vet, men jag var precis i dina skor och trodde att andra ' Google-fu kommer led också här.
Svar
Om du vill ta bort de första två raderna rör det till sed
sed "1,2d"
som i
grep -A 2 "The mail system" mbox_file | sed "1,2d"
Kommentarer
- Du har saknat det faktum att mönstret förekommer många gånger. Om ”E-postsystemet” visas på raderna 4, 14, 24, 34, …, vill OP se raderna 6, 16, 26, 36, … Ditt svar ger 6, 14-16, 24-26, 34- 36,….
Svar
Detta skriver ut nästa 1 rad efter regexp-matchningen med Perl
perl -ne "print if( (/The mail system/ && ($end=1))..!$end-- )"