Como encontrar linhas duplicadas em um arquivo de texto, enquanto algumas podem ser comentadas ou ter diferentes tokens no começo?

5

Eu tenho um arquivo de texto com linhas que são uma mistura como esta:

###  Comments

# Comments
86.242.200.81 banana.domain.net          # comment
86.242.200.3 orange.domain.net
31.28.225.81 monkey.anotherdomain.net

51.18.33.4 puffin.domainz.com
#31.28.220.80 monkey.anotherdomain.net   # comment
86.242.201.3 orange.domain.net

Como encontro as duplicatas host.domain?

Neste caso, existem dois: monkey.anotherdomain.net e orange.domain.net

Tendo em conta que ..

  • Trailing comentários após a entrada precisar ser ignorada, pois eles podem não estar na duplicata.
  • Se a linha estiver comentada, a duplicata ainda deve ser encontrada.
  • As diferenças no endereço IP devem ser ignoradas.
por paradroid 08.08.2015 / 03:45

4 respostas

6

Este foi divertido.

Primeiro, precisamos eliminar os comentários à direita , como em:

86.242.200.81 banana.domain.net          # comment

Podemos fazer isso com o seguinte (assumindo apenas espaços, sem guias):

sed 's/  *#.*//'

Se você tiver guias no arquivo de hosts, talvez execute isso primeiro:

tr '\t' ' '

Em seguida, precisamos eliminar os comentários de "comentar esta linha", os quais definirei como um único caractere de hash que precede um endereço IP. Podemos remover aqueles assim:

sed '/^#[0-9]/ s/^#//'

Colocando o acima juntos, conseguimos:

###  Comments

# Comments
86.242.200.81 banana.domain.net
86.242.200.3 orange.domain.net
31.28.225.81 monkey.anotherdomain.net

51.18.33.4 puffin.domainz.com
31.28.220.80 monkey.anotherdomain.net
86.242.201.3 orange.domain.net

Se classificarmos isso na segunda coluna ( sort -k2 ), obteremos uma lista ordenada por nome:

86.242.200.81 banana.domain.net
# Comments
###  Comments
31.28.220.80 monkey.anotherdomain.net
31.28.225.81 monkey.anotherdomain.net
86.242.200.3 orange.domain.net
86.242.201.3 orange.domain.net
51.18.33.4 puffin.domainz.com

E agora podemos aplicar uniq para encontrar duplicatas, se dissermos que uniq ignora o primeiro campo:

uniq -c -f 1

O que nos dá:

  2 
  1 86.242.200.81 banana.domain.net
  1 # Comments
  1 ###  Comments
  2 31.28.220.80 monkey.anotherdomain.net
  2 86.242.200.3 orange.domain.net
  1 51.18.33.4 puffin.domainz.com

Portanto, se procurarmos linhas com uma contagem de 2 ou mais, encontramos nossas duplicatas. Colocando tudo isso junto, conseguimos:

#!/bin/sh

tr '\t' ' ' |
sed '
    /^#[0-9]/ s/^#//
    s/  *#.*//
    /^ *$/ d
' |
sort -k2 |
uniq -f 1 -c |
awk '$1 > 1 {print}'

A instrução final awk no script acima procura linhas nas quais a contagem de uniq (field1) é > 1 .

A execução do script acima parece este .

    
por 08.08.2015 / 04:04
4

Se linhas de comentários reais como as que você descreveu no início de seus dados existem e devem ser ignoradas, não vejo como o ponto 2 pode ser satisfeito sem algum tipo de suposição em torno de como as linhas comentadas que são materiais podem ser contadas separadamente das linhas comentadas que devem ser ignoradas. Eu fiz a suposição de que as linhas comentadas que são materiais contêm um período no segundo campo.

awk 'NF && $2 ~ /[.]/{++a[$2]}; 
 END{for (k in a) if(a[k] > 1) print k}' file
orange.domain.net
monkey.anotherdomain.net
    
por 08.08.2015 / 04:05
4
sed 's/\(.\)#.*//' file | cut -f 2 -d\ | sort | uniq -d
  • Remover comentários precedidos por qualquer coisa sed 's/\(.\)#.*//'
  • Filtre apenas a segunda coluna cut -f 2 -d\
  • Classifique as linhas para a seguinte comparação sort
  • E só imprime duplicatas uniq -d

Observe que, a menos que seja possível ter uma linha como

86.242.200.81 banana.domain.net#comment

Você pode simplificar o acima para:

cut -f 2 -d\  file | sort | uniq -d

como o comentário seria considerado um terceiro campo.

    
por 08.08.2015 / 14:47
3

Como sobre o caminho curto, fácil e direto?

awk '/#*\d/{print $2}' file | sort | uniq -d

Isso permite relatar duplicatas de host.domain mesmo se eles forem comentados por um sinal de hash (#).

    
por 08.08.2015 / 21:45