Extrai linhas de conjuntos específicos que correspondem a uma regra

3

Eu tenho um arquivo grande com os logs, conforme mostrado abaixo. Existem cerca de 30000 instâncias de tais eventos registrados. Eu preciso extrair essas linhas começando com RINGING e CLOSE (incluído) e que NÃO contém 30 30 .

O requisito é:

Das duas ocorrências abaixo, preciso apenas da instância 2 retida. A Instância 1 precisa ser totalmente excluída (eles formam o grande pedaço do arquivo)

Instância 1:

313782 Aug 19 18:37:04.925: <DATA>  RINGING|254|01136097645|5950|$hostIp|$size  |$data
313783 Aug 19 18:37:05.262: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313784 Aug 19 18:37:09.028: <DATA>  OUT  |254|01136097645|5950|$hostIp|2 bytes  |30 93
313785 Aug 19 18:37:09.705: <DATA>  IN   |254|01136097645|5950|$hostIp|4 bytes  |30 73 F9 F8
313786 Aug 19 18:37:18.532: <DATA>  IN   |254|01136097645|5950|$hostIp|336 bytes  |30 10 60 00 06 00 00 6F 12 00                                                                                 ...
313787 Aug 19 18:37:19.485: <DATA>  OUT  |254|01136097645|5950|$hostIp|133 bytes  |30 30 60 00 00 00 06 6F 12 10                                                                                 ...
313788 Aug 19 18:37:20.898: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313789 Aug 19 18:37:22.006: <DATA>  CLOSE|254|01136097645|5950|$hostIp|$size  |$data

Instância 2:

(a linha com 30 30 não está presente)

313782 Aug 19 18:37:04.925: <DATA>  RINGING|254|01136097645|5950|$hostIp|$size  |$data
313783 Aug 19 18:37:05.262: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313784 Aug 19 18:37:09.028: <DATA>  OUT  |254|01136097645|5950|$hostIp|2 bytes  |30 93
313785 Aug 19 18:37:09.705: <DATA>  IN   |254|01136097645|5950|$hostIp|4 bytes  |30 73 F9 F8
313786 Aug 19 18:37:18.532: <DATA>  IN   |254|01136097645|5950|$hostIp|336 bytes  |30 10 60 00 06 00 00 6F 12 00                                                                                                                                                         ...
313788 Aug 19 18:37:20.898: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313789 Aug 19 18:37:22.006: <DATA>  CLOSE|254|01136097645|5950|$hostIp|$size  |$data
    
por Prabhu 06.09.2014 / 06:17

2 respostas

4

Supondo que seu arquivo de log é chamado logfile , aqui está uma solução awk com a saída de exemplo:

$ awk '/RINGING/,/CLOSE/ {if (/30 30/){f=1}; a=a"\n"$0} f==0 && /CLOSE/ {print a} /CLOSE/{a="";f=0}' logfile    

313782 Aug 19 18:37:04.925: <DATA>  RINGING|254|01136097645|5950|$hostIp|$size  |$data
313783 Aug 19 18:37:05.262: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313784 Aug 19 18:37:09.028: <DATA>  OUT  |254|01136097645|5950|$hostIp|2 bytes  |30 93
313785 Aug 19 18:37:09.705: <DATA>  IN   |254|01136097645|5950|$hostIp|4 bytes  |30 73 F9 F8
313786 Aug 19 18:37:18.532: <DATA>  IN   |254|01136097645|5950|$hostIp|336 bytes  |30 10 60 00 06 00 00 6F 12 00
313788 Aug 19 18:37:20.898: <DATA>  TRAINING|254|01136097645|5950|$hostIp|$size  |$data
313789 Aug 19 18:37:22.006: <DATA>  CLOSE|254|01136097645|5950|$hostIp|$size  |$data

Explicação

Tomando cada comando awk por vez:

  • /RINGING/,/CLOSE/ {if (/30 30/){f=1}; a=a"\n"$0}

    A expressão /RINGING/,/CLOSE/ é um intervalo: especifica que este comando se aplica apenas a grupos de linhas. Um grupo é iniciado quando é encontrada uma linha que inclui o texto RINGING . O grupo termina quando uma linha que inclui o texto CLOSE é encontrada. Para qualquer linha desse grupo, os comandos entre chaves são executados. O primeiro deles define o sinalizador f para um se a linha contiver 30 30 . O segundo comando acrescenta a linha atual à variável a .

  • f==0 && /CLOSE/ {print a}

    Os comandos entre chaves são precedidos por duas condições e juntos. A primeira condição especifica que o sinalizador f é zero (significando que 30 30 não foi encontrado neste grupo) e o segundo especifica que essa linha contém o texto CLOSE . Se ambas as condições forem atendidas, o grupo de linhas, armazenado na variável a , será impresso.

  • /CLOSE/{a="";f=0}

    Por último, em qualquer linha que contenha o texto CLOSE , a variável a será redefinida para a sequência vazia e o sinalizador f será definido como zero. Quando isso é feito, o código é preparado para iniciar no próximo grupo de linhas, se houver um.

por 06.09.2014 / 07:16
2

Pode ser possível usar um regex compatível com perl (PCRE), por exemplo

pcregrep -M '^.*?RINGING(?(?!30 30)(?s).)+?CLOSE.*?$' file

ou

grep -zPo '^.*?RINGING(?(?!30 30)(?s).)+?CLOSE.*?$' file

Alternativamente, usando o separador de registros mais expressivo do GNU awk

gawk -vRS="CLOSE[^\n]*\n" -vORS= '!/30 30/ {print; print RT}' file
    
por 06.09.2014 / 06:43