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 pN 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-- )" 

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *