Apagar linhas que não são n linhas consecutivas começando com o mesmo id

0

Eu tenho um arquivo assim:

194104,41.8,38.3
194104,46.7,39.6
194104,47.4,39.7
194104,49.8,44.3
194104,50.8,47.5
194136,39.9,36.3
194136,45.2,37.8
194170,46.9,42.2
...

Eu quero manter as seis primeiras linhas, começando com 194104, e depois excluir as próximas duas linhas, porque há apenas duas linhas começando com esse número. E assim por diante para o resto do arquivo.

Isso pode ser feito com o sed / awk / grep ou outras ferramentas unix?

    
por vegardstikbakke 30.03.2016 / 10:16

3 respostas

0

Can this be done with sed/awk/grep or other unix tools?

Sim.

...

Isso pode ser feito usando ferramentas como awk ou perl em cerca de 20 linhas de código.

$ cat t.txt
194104,41.8,38.3
194104,46.7,39.6
194104,47.4,39.7
194104,49.8,44.3
194104,50.8,47.5
194136,39.9,36.3
194136,45.2,37.8
194170,46.9,42.2

$ perl t.pl t.txt
194104,41.8,38.3
194104,46.7,39.6
194104,47.4,39.7
194104,49.8,44.3
194104,50.8,47.5

$ wc -l t.pl
19 t.pl

As ideias básicas que usei foram

  • loop over insere uma linha por vez
  • acrescente as linhas a um buffer
  • verifique o valor da primeira palavra
  • conte quantas vezes ele foi visto
  • se diferente, decida se deseja imprimir e liberar buffer, redefinir contagem

Pseudocódigo

Isso corresponde linha a linha com o meu código perl, mas o perl é um pouco mais terser (e eu acaricio minhas elses embora Larry desaprove).

let my minimum be 5
let my buffer be blank
let my count be zero
let my prior first word be blank

while read a line

   if there is a numeric first word followed by a comma 
   then
      if that first word was the same as my prior first word
      then
         increment my count
      otherwise
         if my count is greater than or equal to my minimum
         then
           print my buffer
         end if
         empty my buffer
         let my count be one
      end if
      let my prior first word be the one I just read
      append the line I just read to my buffer
   end if
end while

Provavelmente, isso pode ser feito em menos linhas ou em uma linha mais longa.

    
por 30.03.2016 / 11:38
0

A especificação pode ser um pouco ambígua porque não está claro se você deseja exatamente ou pelo menos seis linhas com o mesmo prefixo. Por outro lado, no seu exemplo existem apenas 5 linhas desse tipo na cabeça que causaram alguma confusão (eu deveria contar antes de fotografar) quando testei isto:

$ cat 6lines.awk
$1 == prev {
   ++cnt
   block = block $0 RS
   if (cnt == 6) {
      printf block
      cnt = 0
      block = ""
   }
   next
}

{
   block = $0 RS
   prev = $1
   cnt = 1
}

awk -F, -f 6lines.awk input

Nós exploramos que o awk pega tudo que não está atribuído como uma string vazia (prev here).

    
por 30.03.2016 / 12:02
0

Isso parece fazer o truque:

perl -F, -ane '
    if ($. > 1) {
        if (@q == 6) { print @q; undef @q }
        elsif ($F[0] ne $prev) { undef @q }
    }
    push @q, $_;
    $prev = $F[0];
    END { if (@q == 6) {print @q} }
'
    
por 31.03.2016 / 02:52