comando para extrair dados entre 2 linhas

2

Eu tenho que extrair a exceção e o rastreamento de pilha correspondente a partir de um número de linha em um arquivo de log. Eu sei que a linha de partida não é do erro. Como posso descobrir onde o rastreamento de pilha terminará no exemplo abaixo? Aprecie sua ajuda

example
-------
2016-10-07 15:49:07,537 ERROR Some exception
 stacktrace line 1
 stacktrace line 2
 .
 .
 stacktrace line n
2016-10-07 15:49:07,539 debug blah blah blah
2016-10-07 15:49:07,540 debug blah blah blah
    
por Shawn 13.10.2016 / 22:18

3 respostas

0

Para resumir, você deseja imprimir linhas começando com o número da linha que você especificou e continuando até pouco antes da primeira linha seguinte que começa com uma data. No seu exemplo, a linha de partida é 3. Nesse caso:

$ awk '{if (NR==3)f=1; else if (/^[0-9-]{10} /)f=0} f{print}' trace.log
2016-10-07 15:49:07,537 ERROR Some exception
 stacktrace line 1
 stacktrace line 2
 .
 .
 stacktrace line n

O código acima funciona da seguinte forma:

  • if (NR==3)f=1

    No número da linha que você especificar, defina a variável f para um.

  • else if (/^[0-9-]{10} /)f=0

    Em outras linhas, defina f para zero se a linha começar com 10 caracteres que são dígitos ou traços seguidos por um espaço. Em outras palavras, defina f para zero na primeira linha que começa com algo que parece uma data.

    Se necessário, podemos usar regexes mais complexas para identificar o início de uma data. Por exemplo, o seguinte requer que a linha comece com algo parecido com um dado, seguido por um espaço, seguido por algo que pareça tempo, seguido por uma vírgula.

    awk '{if (NR==3)f=1; else if (/^[0-9-]{10} [0-9:]{8},/)f=0} f{print}' trace.log
    

    Ainda é possível melhorar ainda mais isso.

  • f{print}

    Se f for diferente de zero, imprima a linha.

    Por questões de brevidade, poderíamos substituir f{print} por apenas f . Isso é possível porque, quando uma ação não é especificada explicitamente, a ação padrão de print é usada.

Alternativa

Algumas versões do awk não suportam fatores de repetição como {10} . Se esse for o caso do seu sistema, tente:

awk '{if (NR==3)f=1; else if (/^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] /)f=0} f{print}' trace.log
    
por 13.10.2016 / 22:24
0

Supondo que todas as linhas de rastreio de pilha iniciem com um espaço em branco (espaço / tabulação), você pode combiná-las ( [[:blank:]] ) no início da linha ( ^ ):

grep '^[[:blank:]]' file.log
    
por 13.10.2016 / 22:24
0

Se o rastreio que você deseja extrair começar na linha 2 de trace.log , e seu final é indicado por uma linha que começa com uma data no formato AAAA-MM-DD (e não há tais linhas com o traço), então

sed -nE '2,/^[0-9]{4}-[0-9]{2}-[0-9]{2} /p' trace.log

imprime todas as linhas da linha 2 até linha n +3 (a primeira linha após o rastreio que começa com uma data). Desde que você não quer que a última linha, canalize o acima em um comando que remova a última linha:

sed -nE '2,/^[0-9]{4}-[0-9]{2}-[0-9]{2} /p' trace.log | head -n -1

ou

sed -nE '2,/^[0-9]{4}-[0-9]{2}-[0-9]{2} /p' trace.log | sed '$d'

Se você precisar procurar uma data e uma hora , pesquise

^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}
    
por 13.10.2016 / 23:05