As linhas de extração apareceram consecutivamente por 3 vezes ou mais no Linux

2

Eu tenho uma tabela no Linux:

A 0
A 0
A 0
B 0
B 1
B 0
B 1
B 0

Eu quero extrair linhas que aparecem consecutivamente por 3 vezes ou mais.

Minha saída esperada é:

A 0

Na verdade, 3 vezes ou mais é apenas um exemplo simplificado. A situação real é que eu quero extrair linhas que aparecem consecutivamente por 30 vezes mais.

Alguma ideia?

Obrigado!

    
por Johnny Tam 14.09.2017 / 10:02

4 respostas

5
uniq -c file | awk '$1 >= 3 { print $2,$3 }'

O uniq -c produzirá cada linha junto com uma contagem de quantas vezes essa linha ocorrerá consecutivamente. Para os dados fornecidos, produzirá

   3 A 0
   1 B 0
   1 B 1
   1 B 0
   1 B 1
   1 B 0

O script awk receberá isso e exibirá os dois últimos campos se o primeiro campo for maior ou igual a 3.

O resultado será

A 0
    
por 14.09.2017 / 10:11
1

Simples awk pode ser usado da seguinte forma.

awk '{!s[$0]++} END{for (x in s) if (s[x]>2) print x}' infile

Isto está imprimindo as linhas onde estas são repetidas mais de 2 vezes >2 mas no total. Você pode definir >29 para obter linhas repetidas ≥ 30 vezes.

Você pode usar o comando da seguinte maneira, conforme indicado por @Philippos, para imprimir somente linhas consecutivas repetidas ≥ 3 vezes.

awk 'p!=$0{n=0} {p=$0;n++} (n==3)'

Explicação: Armazene a linha anterior em p , conte as linhas em n e redefina o contador se uma linha for diferente da anterior. Imprima na ocorrência 3 rd (ou 30 th ).

Ou mesmo na abordagem curta, que faz o mesmo:

awk 'p!=$0{n=0;p=$0} ++n==3'
    
por 14.09.2017 / 11:27
1

Está faltando uma versão sed pura! Isso fará:

sed 'x;G;s/\(.*\)\n$/+/;/\n/d;h;s/^+\{2\}//;/^+/d' file

Substitua o 2 por 29 por 30 linhas consecutivas. Eu me pergunto se isso pode ser otimizado de alguma forma.

Como funciona: No espaço de espera, a linha anterior é mantida, com um + para cada ocorrência adicional. Agora, para cada linha, o x troca os buffers, portanto, a linha atual está no espaço de armazenamento. O G anexa o espaço de espera, portanto, no espaço de padrão, temos a linha antiga e a nova, separadas por uma nova linha. Agora, se a linha aparecer antes e depois da nova linha, teremos duas linhas idênticas e o comando s substituirá uma delas pela nova linha por + . Se ainda houver uma nova linha no padrão, as linhas serão diferentes e poderemos iniciar um novo ciclo ( /\n/d ). Caso contrário, copie a linha modificada para o espaço de espera para coletar o + . Por fim, remova quantas + as linhas forem necessárias (menos um). Se ainda houver um + líder, teríamos linhas demais ou não suficientes, então d elete.

    
por 15.09.2017 / 09:13
0

Com script único awk :

awk '{k=$1 FS $2}!a[k] || (NR==n && k==pk){ a[k]++; pk=k; n=NR+1 }
     END{ for(i in a) if(a[i] >=3) print i }' file
  • k=$1 FS $2 - chave crucial, concatenação do 1º e 2º campos

  • !a[k] || (NR==n && k==pk) - verifique se o registro ocorre pela primeira vez OU se é simultâneo ao registro anterior

A saída:

A 0
    
por 14.09.2017 / 10:44