Estou analisando um arquivo de caixa de correio que armazena relatórios do servidor de e-mail para e-mails entregues sem sucesso. Desejo extrair endereços de e-mail inválidos, então para removê-los do sistema. O arquivo de registro se parece com isto:
...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 após uma linha com “O sistema de correio” . Usar grep dessa forma me dá a linha “O sistema de e-mail” e as próximas duas linhas:
grep -A 2 "The mail system" mbox_file
No entanto, eu não sei como remover o Linha “The mail system” e a segunda linha vazia desta saída. Acho que poderia escrever um script PHP / Perl / Python para fazer isso, mas me pergunto se isso é possível com grep ou alguma outra ferramenta padrão. Tentei atribuir um deslocamento negativo ao parâmetro -B:
grep -A 2 -B -2 "The mail system" mbox_file
Mas grep reclama:
grep: -2: invalid context length argument
Existe uma maneira de fazer isso com grep?
Comentários
- -B aceita numeral como -A faria, e iria exibir o linhas anteriores antes da partida.
- Sim, é verdade, mas Milan não está ' interessado no que antecede a partida. . O problema que ele encontrou é que -A e -B aceitam apenas valores positivos … e que, em qualquer caso, -A e -B não podem ' ser usados um em relação ao outro , como ele tentou fazer.
- Hum, só para ter certeza: esses são endereços fictícios que você não extraiu (diretamente) do arquivo que recebeu, certo?
- @Matthieu M. não, eles são de um arquivo de log real. Percebi que, já que são endereços inválidos de qualquer maneira, qual ' é o ponto de inventar endereços fictícios que podem ser válidos.
- stackoverflow.com/questions/8101701/…
Resposta
A maneira mais simples de resolver usando apenas grep
é 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*$"
Resposta
Se você não estiver preso a usando grep
, tente sed
…
sed -n "/The mail system/{n;n;p}"
Quando encontra uma linha contendo “O sistema de correio”, lê a próxima linha duas vezes, através do n;n;
, descartando cada linha anterior ao fazê-lo.
Isso deixa a terceira linha do seu grupo no espaço do padrão, que é então impresso pelo comando sed “s p
. A opção -n
principal impede todas as outras impressões .
Para imprimir as próximas duas linhas também, é apenas o 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 do padrão,
Aqui está a versão condensada final …
sed -n "/The mail system/{n;n;N;N;p}"
Se você quiser um separador de grupo , semelhante ao que grep produziria, você pode usar o comando sed “s insert 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á o resultado da primeira correspondência:
<[email protected]>: host mx1.hotmail.com[65.54.188.94] said: 550 Requested action not taken: mailbox unavailable (in reply to RCPT TO command) --
Comentários
- +1. Obrigado. Eu não ' não preciso disso neste caso, mas eu ' vou manter isso marcado para o caso de eu conseguir coisas mais complicadas para lidar.
- Esta é uma ótima resposta!
Resposta
grep -A 2 -B -2 "The mail system" mbox_file
-B
é para as linhas anteriores, portanto, não há necessidade de fornecer o valor -negativo.
grep -A 2 -B 2 "The mail system" mbox_file # This will work please check
Comentários
- Isso não responde à pergunta.
-A 2 -B 2
imprime de duas linhas antes do contexto a 2 linhas depois do contexto. A questão é sobre a impressão de 2 linhas após o contexto para 4 linhas após o contexto.
Resposta
I não vejo por que usar apenas grep (s), exceto se for uma restrição estrita. Não pode ser feito com uma chamada para grep.
grep -A 2 "The mail system" mbox_file | tail -n +3
- grep: Encontre a linha e produza 2 linhas depois,
- tail: corte as 2 primeiras linhas (ou seja, comece na terceira linha).
Comentários
- Isso só funciona se houver uma única linha correspondente, o que provavelmente não é o que a pergunta está perguntando.
- Isso não é nada que a pergunta pediu, mas me ajuda na minha situação atual :-).
- @ daniel.neumann Eu sei, mas estava exatamente no seu lugar e pensei que os outros ' Google-fu vão liderar aqui também.
Resposta
Se quiser remover as primeiras 2 linhas, canalize para sed
sed "1,2d"
como em
grep -A 2 "The mail system" mbox_file | sed "1,2d"
Comentários
- Você não percebeu que o padrão ocorre muitas vezes. Se “O sistema de correio” aparecer nas linhas 4, 14, 24, 34, …, o OP deseja ver as linhas 6, 16, 26, 36, … Sua resposta dará 6, 14-16, 24-26, 34- 36,….
Resposta
Isso imprime a próxima linha 1 após a correspondência regexp, usando Perl
perl -ne "print if( (/The mail system/ && ($end=1))..!$end-- )"