Analyzuji soubor poštovní schránky, který ukládá zprávy e-mailového serveru pro neúspěšně doručený e-mail. Chci extrahovat špatné e-mailové adresy, takže že je odstraním ze systému. Soubor protokolu vypadá takto:
...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-mailová adresa je uvedena za 2 řádky za řádkem s „Poštovní systém“ . Takové použití grepu mi dává řádek „The mail system“ a další dva řádky:
grep -A 2 "The mail system" mbox_file
Nevím však, jak odstranit Řádek „Poštovní systém“ a druhý prázdný řádek z tohoto výstupu. Myslím, že bych k tomu mohl napsat skript PHP / Perl / Python, ale zajímalo by mě, jestli je to možné pomocí grepu nebo jiného standardního nástroje. Snažil jsem se dát negativní offset parametru -B:
grep -A 2 -B -2 "The mail system" mbox_file
Ale grep si stěžuje:
grep: -2: invalid context length argument
Existuje způsob, jak to provést pomocí grep?
Komentáře
- -B přijímá číslici jako -A a zobrazí by předchozí řádky před zápasem.
- Ano, to je pravda, ale Milan se ' nezajímá, co předchází zápasu .. . Problém, s nímž se setkal, je, že -A a -B přijímají pouze kladné hodnoty … a že v každém případě -A a -B nelze ' vzájemně použít , jak se o to pokusil.
- Hum, jen pro jistotu: jedná se o fiktivní adresy, které jste (přímo) nezískali ze souboru, který jste dostali, že?
- @ Matthieu M. ne, jsou ze skutečného souboru protokolu. Myslel jsem, že stejně jsou to neplatné adresy, jaký ' má smysl vymýšlet fiktivní adresy, které by mohly být platné.
- stackoverflow.com/questions/8101701/…
odpověď
Nejjednodušší způsob, jak to vyřešit pouze pomocí grep
, je na konec přivést ještě jednu obrácenou grep
. Například:
grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v "^\d*$"
Odpovědět
Pokud nejste přihlášeni pomocí grep
zkuste sed
…
sed -n "/The mail system/{n;n;p}"
Když najde řádek obsahující „Poštovní systém“, přečte další řádek dvakrát pomocí n;n;
, přičemž zahodí každý předchozí řádek.
Tím se ponechá třetí řádek vaší skupiny v prostoru vzorů, který se poté vytiskne pomocí příkazu sed „s p
.. Přední -n
možnost zabrání veškerému dalšímu tisku .
Chcete-li vytisknout také další dva řádky, je to jen případ next a print n;p
ještě dvakrát.
sed -n "/The mail system/{n; n;p; n;p; n;p}"
Čtení dalšího řádku pro požadované řádky lze hromadit a vytisknout jeden blok pouze s jedním p
… N
načte další řádek a připojí jej do prostoru vzoru,
Zde je konečná zhuštěná verze …
sed -n "/The mail system/{n;n;N;N;p}"
Pokud chcete oddělovač skupin , podobný tomu, jaký by měl grep výstup, můžete použít příkaz sed „s insert i
(což musí být poslední příkaz na řádku) …
Zde je syntaxe, která obsahuje oddělovač skupin
sed -n "/The mail system/{n;n;N;N;p;i-- }" > output-file # or | ...
Zde je výstup pro první shodu:
<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550 Requested action not taken: mailbox unavailable (in reply to RCPT TO command) --
Komentáře
- +1. Děkuji. V tomto případě to ' nepotřebuji, ale ' Tuto záložku si ponechám pro případ, že bych zvládl složitější věci.
- To je skvělá odpověď!
Odpověď
grep -A 2 -B -2 "The mail system" mbox_file
-B
je pro předchozí řádky, takže není nutné uvádět -negativní hodnotu.
grep -A 2 -B 2 "The mail system" mbox_file # This will work please check
Komentáře
- To na otázku neodpovídá.
-A 2 -B 2
tiskne ze dvou řádků před kontextem na 2 řádky za kontextem. Otázkou je tisk ze 2 řádků za kontextem do 4 řádků za kontextem.
Odpověď
I nevidí smysl používat pouze grep (y), kromě případů, kdy je to přísné omezení. Nelze to provést pomocí jediného volání grep.
grep -A 2 "The mail system" mbox_file | tail -n +3
- grep: Najděte řádek a vypište 2 řádky za,
- ocas: ořízněte první 2 řádky (tj. začněte od třetího řádku).
Komentáře
- Funguje to pouze v případě, že existuje jeden odpovídající řádek, což pravděpodobně není to, na co se otázka ptá.
- To není to, na co se otázka ptá, ale to pomáhá mi v mé současné situaci :-).
- @ daniel.neumann vím, ale byl jsem přesně ve tvých botách a myslel jsem si, že ostatní ' Google-fu bude vést také sem.
Odpověď
Pokud chcete odstranit první 2 řádky, přejděte do sed
sed "1,2d"
jako v
grep -A 2 "The mail system" mbox_file | sed "1,2d"
Komentáře
- Chybělo vám, že se vzor vyskytuje mnohokrát. Pokud se na řádcích 4, 14, 24, 34,… objeví „Poštovní systém“, OP chce vidět řádky 6, 16, 26, 36, … Vaše odpověď bude 6, 14-16, 24-26, 34- 36,….
Odpověď
Tím se vytiskne další 1 řádek následující po shodě regexp pomocí Perlu
perl -ne "print if( (/The mail system/ && ($end=1))..!$end-- )"