Remove parcial duplica linhas consecutivas mas mantém primeiro e por último

3

Eu tenho arquivos de log com um registro de data e hora e seis valores em cada linha Eu quero reduzir a quantidade de dados, removendo linhas consecutivas com os mesmos valores (ignorando carimbos de hora) e mantendo a primeira e última linha de cada conjunto duplicado. De preferência usando um script bash. Deve ser uma combinação mágica de comando sed ou awk .

Mesmo que eu tenha que analisar o arquivo várias vezes, ler 3 linhas de cada vez e remover a do meio, é uma boa solução.

arquivo original:

1447790360      99999   99999   20.25   20.25   20.25   20.50
1447790362      20.25   20.25   20.25   20.25   20.25   20.50
1447790365      20.25   20.25   20.25   20.25   20.25   20.50
1447790368      20.25   20.25   20.25   20.25   20.25   20.50
1447790371      20.25   20.25   20.25   20.25   20.25   20.50
1447790374      20.25   20.25   20.25   20.25   20.25   20.50
1447790377      20.25   20.25   20.25   20.25   20.25   20.50
1447790380      20.25   20.25   20.25   20.25   20.25   20.50
1447790383      20.25   20.25   20.25   20.25   20.25   20.50
1447790386      20.25   20.25   20.25   20.25   20.25   20.50
1447790388      20.25   20.25   99999   99999   99999   99999
1447790389      99999   99999   20.25   20.25   20.25   20.50
1447790391      20.00   20.25   20.25   20.25   20.25   20.50
1447790394      20.25   20.25   20.25   20.25   20.25   20.50
1447790397      20.25   20.25   20.25   20.25   20.25   20.50
1447790400      20.25   20.25   20.25   20.25   20.25   20.50

resultado desejado:

1447790360      99999   99999   20.25   20.25   20.25   20.50
1447790362      20.25   20.25   20.25   20.25   20.25   20.50
1447790386      20.25   20.25   20.25   20.25   20.25   20.50
1447790388      20.25   20.25   99999   99999   99999   99999
1447790389      99999   99999   20.25   20.25   20.25   20.50
1447790391      20.00   20.25   20.25   20.25   20.25   20.50
1447790394      20.25   20.25   20.25   20.25   20.25   20.50
1447790400      20.25   20.25   20.25   20.25   20.25   20.50
    
por athan nats 22.11.2015 / 00:23

4 respostas

1

Com awk um revestimento:

awk '{n=$2$3$4$5$6$7}l1!=n{if(p)print l0; print; p=0}l1==n{p=1}{l0=$0; l1=n}END{print}' file

O ponto principal é manipular algumas variáveis: n armazena todos os campos, exceto primeiro na linha atual, l1 o mesmo para a linha anterior e l0 para toda a linha anterior. O p é apenas um sinalizador para marcar se a linha anterior já foi impressa.

    
por 22.11.2015 / 01:28
0

Perl para o resgate:

perl -ne '($t, $r) = /([0-9]+\s+)(.*)/;
          print "$pt$p\n$_" if $r ne $p;
          $p = $r;
          $pt = $t;
          }{
          print $t, $r' input-file \
| sort -nu | tail -n+2
  • -n lê a linha de entrada por linha.
  • $t é o timestamp mais espaço em branco, $r é o "restante".
  • $p é o restante anterior, $pt é o registro de data e hora anterior.
  • a última linha é sempre impressa

Perl imprime algumas linhas duas vezes, sort -nu deve remover as duplicatas. tail remove a primeira linha vazia.

    
por 22.11.2015 / 00:44
0

Uma versão do awk:

#!/usr/bin/gawk -f

BEGIN                      { rep=0  ; prev="" ; OFS=FS="     "}
!rep && prev== $2          { rep=1  ; prev=$2 ;          next }
rep  && prev== $2          { time=$1 ;                   next }
rep  && prev!= $2          { rep=0  ; print time, prev;       }
                           { print  ; prev=$2                 }
END                        { if(rep){ print time, prev}       }
  • rep = dentro de uma repetição?
  • prev = valores numéricos anteriores
  • time = carimbo de data / hora anterior
por 22.11.2015 / 01:13
0
sed -e:t -e'$!{1N;N;s/\( .*\)\(\n[^ ]*\)\{2\}$//;tt' -e'P;D;}' <in >out

... isso funciona. recursivamente substitui o segundo em uma série de três linhas de entrada que ele considera idênticas do segundo campo delimitado por espaço em. ele continuará a desenhar outra linha de entrada para substituir cada uma, substituindo-a até que não consiga mais fazê-lo. somente quando ele não pode igualar três linhas similares, P rint o primeiro em seu buffer antes de D eletê-lo e voltar para tentar novamente com os dois que permanecem e a próxima linha de entrada.

com GNU ou BSD sed :

sed -Ee:t -e'1N;$!N;s/( .*)(\n[^ ]*){2}$//;tt' -eP\;D <in >out
1447790360      99999   99999   20.25   20.25   20.25   20.50
1447790362      20.25   20.25   20.25   20.25   20.25   20.50
1447790386      20.25   20.25   20.25   20.25   20.25   20.50
1447790388      20.25   20.25   99999   99999   99999   99999
1447790389      99999   99999   20.25   20.25   20.25   20.50
1447790391      20.00   20.25   20.25   20.25   20.25   20.50
1447790394      20.25   20.25   20.25   20.25   20.25   20.50
1447790400      20.25   20.25   20.25   20.25   20.25   20.50
    
por 22.11.2015 / 16:20