A maneira mais simples de resolvê-lo usando grep
apenas é canalizar mais um grep
invertido no final.
Por exemplo:
grep -A 4 "The mail system" temp.txt | grep -v "The mail system" | grep -v '^\d*$'
Estou analisando um arquivo de caixa de correio que armazena relatórios de servidor de email para emails entregues sem êxito. Desejo extrair endereços de e-mail inválidos, para que eu os remova do sistema. O arquivo de log é assim:
...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.
O endereço de e-mail vem 2 linhas depois de uma linha com "O sistema de e-mail". Usar o grep assim me fornece a linha "O sistema de mensagens" e as próximas duas linhas:
grep -A 2 "The mail system" mbox_file
No entanto, não sei como remover a linha "The mail system" e a segunda linha vazia dessa saída. Eu acho que eu poderia escrever script PHP / Perl / Python para fazer isso, mas eu me pergunto se isso é possível com o grep ou alguma outra ferramenta padrão. Eu tentei dar offset negativo para o parâmetro -B:
grep -A 2 -B -2 "The mail system" mbox_file
Mas o grep reclama:
grep: -2: invalid context length argument
Existe uma maneira de fazer isso com o grep?
Se você não estiver bloqueado para usar grep
, tente sed
...
sed -n '/The mail system/{n;n;p}'
Quando encontrar uma linha contendo "O sistema de correio", ele lerá a próxima linha duas vezes, por meio do n;n;
, descartando cada linha anterior da mesma forma.
Isso deixa a terceira linha do grupo no espaço padrão, que é então impressa através do comando p
do sed. A opção -n
principal impede todas as outras impressões.
Para imprimir as próximas duas linhas também, é apenas um caso de próximo e imprimir n;p
mais duas vezes.
sed -n '/The mail system/{n; n;p; n;p; n;p}'
As leituras da próxima linha para as linhas que você precisa podem ser acumuladas e impressas em um único bloco com apenas um p
... N
lê a próxima linha e a anexa ao espaço padrão,
Aqui está a versão condensada final ...
sed -n '/The mail system/{n;n;N;N;p}'
Se você quiser um grupo seperator , similar ao que o grep wouuld produz, você pode usar o comando insert do sed i
(que deve ser o último comando em uma linha ) ...
Aqui está a sintaxe para incluir um separador de grupo
sed -n '/The mail system/{n;n;N;N;p;i--
}' > output-file # or | ...
Aqui está a saída para o primeiro jogo:
<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550
Requested action not taken: mailbox unavailable (in reply to RCPT TO
command)
--
grep -A 2 -B -2 "The mail system" mbox_file
-B
é para linhas anteriores, portanto, não há necessidade de fornecer um valor negativo.
grep -A 2 -B 2 "The mail system" mbox_file # This will work please check
Não vejo sentido em usar apenas grep (s), exceto se for uma restrição estrita. Não pode ser feito com uma chamada para o grep.
grep -A 2 "The mail system" mbox_file | tail -n +3
Isso imprime a próxima linha 1 após a correspondência de expressão regular, usando Perl
perl -ne 'print if( (/The mail system/ && ($end=1))..!$end-- )'
Tags grep