Converte multilinhas para uma única linha

2

Eu tenho um arquivo de log de várias linhas e quero convertê-lo em um log de linha única.

Exemplo multilinha:

6/13/2015 12:00:47 AM - {   562} START Web 
6/13/2015 12:00:47 AM - Requested Web connection from 123.125.71.103 [123.125.71.103], ID=562 
6/13/2015 12:01:24 AM - {   563} START POP3 
6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=563 
6/13/2015 12:01:24 AM - (   563) USER [email protected] 
6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=563 
6/13/2015 12:01:24 AM - {   563} END POP3
6/13/2015 12:01:24 AM - {   564} START POP3 
6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=564 
6/13/2015 12:01:24 AM - (   564) USER [email protected] 
6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=564 
6/13/2015 12:01:24 AM - {   564} END POP3
6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ID=562 
6/13/2015 12:01:40 AM - {   562} END Web

Para começar, eu gostaria de uma saída de linha única como essa, onde eu corresponda aos mesmos IDs de log (por exemplo, "562").

6/13/2015 12:00:47 AM - {   562} START Web 6/13/2015 12:00:47 AM - Requested Web connection from 123.125.71.103 [123.125.71.103], ID=562 6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ID=562 6/13/2015 12:01:40 AM - {   562} END Web
6/13/2015 12:01:24 AM - {   563} START POP3 6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=563 6/13/2015 12:01:24 AM - (   563) USER [email protected]  6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=563  6/13/2015 12:01:24 AM - {   563} END POP3
6/13/2015 12:01:24 AM - {   564} START POP3 6/13/2015 12:01:24 AM - Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=564 6/13/2015 12:01:24 AM - (   564) USER [email protected]  6/13/2015 12:01:24 AM - POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=564  6/13/2015 12:01:24 AM - {   564} END POP3

Eu fiz o seguinte script bash que não está funcionando como esperado, já que está mesclando todas as mensagens "POP3" ou "Web" para uma única linha e não separando-as com base no ID da mensagem.

Script:

#!/bin/bash

HOME=/var/tmp/test.txt

ID='((awk '$6 ~/[0-9]\W/ {print $6}' $HOME | awk '{gsub (/)/, ""); print}' | awk '{gsub (/}/, ""); print}') && (awk '$11 ~/[0-9]/ {print $11}' $HOME | awk '{gsub ("ID=", ""); print}'))'


for ID in $HOME
do
        awk '!/Web/' $HOME | xargs >> final.txt
        awk '/Web/' $HOME | xargs >> final.txt
done

Alguma sugestão de como eu deveria criar um loop para mesclar apenas os mesmos IDs?

    
por mmesojedec 26.07.2015 / 11:25

4 respostas

0

Se você conseguir apenas os timestamps, o seguinte é suficiente:

sed -e:n -e'$!N;s/^\(\([^-]*-\).*\)\n */:::/;tn' -eP\;D <in >out

Anexa recursivamente a linha N ext à linha atual e, se todos os caracteres na linha atual, incluindo o primeiro - traço, puderem corresponder ao cabeçalho da linha anexada, os dois são unidos e o registro de data e hora anexado é removido. Se s/// ubstitution t ests for bem-sucedida, sed será ramificado para o rótulo :n para outra linha N ew, caso contrário, todos os dados mesclados pendentes serão P rinted para stdout antes de ser D é eliminado e sed recomeça a partir do topo para tentar novamente.

Dados seus dados de amostra, imprime:

6/13/2015 12:00:47 AM - {   562} START Web ::: Requested Web connection from 123.125.71.103 [123.125.71.103], ID=562
6/13/2015 12:01:24 AM - {   563} START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=563 ::: (   563) USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=563 ::: {   563} END POP3::: {   564} START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37], ID=564 ::: (   564) USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ID=564 ::: {   564} END POP3
6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ID=562 ::: {   562} END Web

Mas isso não é muito bom, aparentemente. Parece que você quer mesclar ID - desculpe por isso. O que se segue funciona - também apaga carimbos de data / hora e IDS repetitivos conforme ocorre na entrada.

sed   -e'y/)},={/(((((/' \
      -e's/-\([^(I]*\)[^0-9]*\([0-9]*\)[( ]*/-  -/;=' |
paste -d- - - |
sort -t- -nk3,3 -nk1,1 |
sed   -e's/^[^-]*-//;:n' -e'h;$!N' \
      -e's/\(-\([^-]*-\).*[^ ]\) *\n\([^-]*-\)\{2\}/ - /;tn' \
      -ex\;:t -e's/\(\([^-]*-\)[^/]*\)- */:::/;tt'   -e'p;g;D'
6/13/2015 12:00:47 AM - 562 - START Web ::: Requested Web connection from 123.125.71.103 [123.125.71.103] - 6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended. ::: END Web
6/13/2015 12:01:24 AM - 563 - START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37] ::: USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ::: END POP3
6/13/2015 12:01:24 AM - 564 - START POP3 ::: Requested POP3 connection from 10.127.251.37 [10.127.251.37] ::: USER [email protected] ::: POP3 connection with 10.127.251.37 [10.127.251.37] ended. ::: END POP3
    
por 26.07.2015 / 19:41
2

Você pode fazer tudo no awk. O seguinte combina os IDs conforme foram lidos.

awk  '{
    line = $0;
    # ID is { XXX } or ( XXX )
    if ( /[{(] *[0-9]+[})]/ ) {
        id = $0;
        sub(/ *[})].*/,"", id);
        sub(/.*[({] */,"", id);
    }
    # ID is ID=XXX
    else if ( $NF ~ /ID=/ ) {
        id = $NF;
        sub(/[^=]*=/,"",id);
    }
    # else ID= previous value

    # save line into a assoc. array of IDs
    final[id] = final[id]""line" "; # add space between lines
}
END {
    # print foreach id
    for ( id in final ) {
        print final[id];
    }
}
' /var/tmp/text.txt

Você pode reduzir as informações supérfluas, como a impressão dos códigos e, em vez disso, apenas usar um prefixo, por exemplo,

     # remove ID
     sub(/ID=[0-9]/,"",id);
     sub(/[({] *[0-9]+[})]/,"",id);

     END {
         # print foreach id
         for ( id in final ) {
             #Print ID then the rest of the line
             printf("[ID=%d]: %s\n", id, final[id]);
         }
     }
    
por 26.07.2015 / 13:47
1

Com base na abordagem @mikeserv, estou recebendo a seguinte saída.

SCRIPT:

(   sed   -e'y/)},={/(((((/' \
          -e's/-\([^(I]*\)[^0-9]*\([0-9]*\)[( ]*/-  -/;=' |
    paste -d- - - |
    sort  -t- -nk3,3 -nk1,1 |
    sed   -e's/^[^-]*-//;:n' -e'h;$!N' \
          -e's/\(-\([^-]*-\).*[^ ]\) *\n\([^-]*-\)\{2\}/ - /;tn' \
          -ex\;:t -e's/\(\([^-]*-\)[^/]*\) - */,/;tt'   -e'p;g;D'
)   < in.txt > out.txt
6/13/2015 12:00:47 AM - 562 - START Web, Requested Web connection from 123.125.71.103 [123.125.71.103] - 6/13/2015 12:01:40 AM - Web connection with 123.125.71.103 [123.125.71.103] ended., END Web
6/13/2015 12:01:24 AM - 563 - START POP3, Requested POP3 connection from 10.127.251.37 [10.127.251.37], +OK ArGoSoft Mail Server Pro for WinNT/2000/XP( Version 1.8 (1.8.9.6( - 6/13/2015 12:01:24 AM - CAPA, -ERR Unknown command, USER [email protected], +OK Password required for [email protected], PASS XXXXXXXXX, +OK Mailbox locked and ready, Adding address to POP Before SMTP manager, STAT, +OK 178 97537344, UIDL, +OK, ., LIST, +OK, ., QUIT, +OK Aba he, POP3 connection with 10.127.251.37 [10.127.251.37] ended., END POP3
6/13/2015 12:04:25 AM - 564 - START POP3, Requested POP3 connection from 10.127.251.37 [10.127.251.37], +OK ArGoSoft Mail Server Pro for WinNT/2000/XP( Version 1.8 (1.8.9.6( - 6/13/2015 12:04:25 AM - CAPA, -ERR Unknown command, USER [email protected], +OK Password required for [email protected], PASS XXXXXXXXX, +OK Mailbox locked and ready, Adding address to POP Before SMTP manager, STAT, +OK 178 97537344, UIDL, +OK, ., LIST, +OK, . - 6/13/2015 12:04:26 AM - QUIT, +OK Aba he, POP3 connection with 10.127.251.37 [10.127.251.37] ended., END POP3
6/13/2015 12:04:36 AM - 565 - START Web, Requested Web connection from 31.133.9.16 [31.133.9.16], Web connection with 31.133.9.16 [31.133.9.16] ended., END Web
6/13/2015 12:07:26 AM - 566 - START POP3, Requested POP3 connection from 10.127.251.37 [10.127.251.37], +OK ArGoSoft Mail Server Pro for WinNT/2000/XP( Version 1.8 (1.8.9.6( - 6/13/2015 12:04:25 AM - CAPA, -ERR Unknown command, USER [email protected], +OK Password required for [email protected], PASS XXXXXXXXX, +OK Mailbox locked and ready, Adding address to POP Before SMTP manager, STAT, +OK 178 97537344, UIDL, +OK, ., LIST, +OK, . - 6/13/2015 12:04:26 AM - QUIT, +OK Aba he, POP3 connection with 10.127.251.37 [10.127.251.37] ended., END POP3

Você pode ver que neste exemplo na linha 4 estamos perdendo o registro de data e hora antes que "a conexão da Web com 31.133.9.16 [31.133.9.16] tenha terminado.". Este será o mesmo problema para todos os logs semelhantes, começando com "Conexão da Web .....". Para todos os outros registros que contenham mensagens POP3, tudo está OK.

Como devo modificar o comando sed para incluir também o registro de data e hora para todas as mensagens "Conexão da Web ...." restantes e não apenas a primeira?

    
por 27.07.2015 / 10:33
0

Assim como os IDs em cada linha no 6º campo ou no campo antes de recuperar todas as linhas por ID é possível sem / sub

awk -F"[ }=)]+" '
NF{
    if($6 ~ "[0-9]{3}")
        ids=$6
    else 
        ids=$(NF-1)

    if(!M[ids])
        M[ids]=$0
    else
        M[ids]=M[ids] " " $0
}
END{
    for(i in M)
        print M[i]
}' /var/tmp/text.txt
    
por 26.07.2015 / 15:47