Contando o número de vezes que cada endereço IP aparece no arquivo de log

9

Eu tenho um arquivo no formato da seguinte maneira:

$ cat file.txt

27.33.65.2
27.33.65.2
58.161.137.7
121.50.198.5
184.173.187.1
184.173.187.1
184.173.187.1

Qual é a melhor maneira de analisar o arquivo file.txtem um formato como:

27.33.65.2: 2
58.161.137.7: 1
121.50.198.5: 1
184.173.187.1: 3

Em outras palavras, desejo percorrer o arquivo e contar o número de vezes que cada endereço IP aparece. Eu já o executei sortpara que todos os endereços IP estejam em ordem e diretamente um após o outro.

James Spittal
fonte
Pessoalmente, eu importaria esse tipo de arquivo em um banco de dados próximo acessível (criando uma tabela temporária em qualquer instância do postgres que eu tenha aqui), seguida por uma ação rápida do SQL e exportando de volta para um arquivo de texto.
oakad

Respostas:

23

Você está procurando uniq -c

Se a saída não for do seu agrado, ela poderá ser analisada e reformatada prontamente.

Por exemplo:

$ uniq -c logfile.txt | awk '{print $2": "$1}'
27.33.65.2: 2
58.161.137.7: 1
121.50.198.5: 1
184.173.187.1: 3
Glenn Jackman
fonte
Combinando uniqe awknão parece ser uma grande abordagem para mim ...
Hauke Laging
3
Como uniqfunciona apenas na entrada classificada (corresponde a linhas correspondentes adjacentes, não a linhas do arquivo).
oakad
1
Você deve classificar os resultados antes de enviá-los para a uniq. Se você ler o Q original, o OP indica que ele já classificou os resultados usando sort!
Slm
2
@HaukeLaging - Agradeço o que você está dizendo, mas da mesma maneira que a maioria dos usuários de computadores nunca se aventurará além do OSX e do Windows, ainda mais a maioria dos usuários do Unix não se aventurará além do uso de ferramentas designadas para tarefas específicas. O uso do AWK não é para os fracos de coração, veja o que você deve fazer para executar esta tarefa básica usando o AWK versus o que a solução de Glenn exigia. Acho que estou sendo justo ao dizer que a solução dele é mais simples de entender mentalmente, embora a sua seja provavelmente mais eficiente. BTW, eu fiz UV tanto desde que ambos estão corretos!
Slm
1
@HaukeLaging - Sim, exatamente. À medida que você percorre o site, nossas responsabilidades mudam um pouco, IMO. Somos responsáveis ​​por fazer A'ers abrangentes e observar os A'ers que fornecemos como momentos de ensino para o OP e para todos os futuros visitantes que o encontrarem, novamente IMO. Mas é uma escolha pessoal, portanto, se você tiver apenas alguns minutos de sobra, fornecer um A de qualquer forma será sempre apreciado.
Slm
6

uniqparece ser a solução mais inteligente, de fato. A maneira inábil:

awk '{ip_count[$0]++}; '\
'END {for (ip in ip_count) printf "%15s: %d\n",ip,ip_count[ip];}' file
Hauke ​​Laging
fonte
+1. Se a ordem da saída for importante para o OP, esta resposta não garante: a iteração sobre as chaves de uma matriz associativa não tem ordem inerente.
Glenn Jackman
@glennjackman Mas adicionar sortà minha resposta ainda é mais rápido, pois menos itens precisam ser classificados. ;-)
Hauke ​​Laging
Oh sim? OH SIM?!? ;) a entrada já está classificada. Essa resposta estranha os embaralha, então ainda dá mais trabalho. Nyah! ;)
glenn jackman
0

arquivo de ordenação mais firmado, em seguida, obtenha a contagem por unic -c

sort filename | uniq -c

Aeyd Moeyd
fonte
1
O arquivo já está classificado (de acordo com o usuário na pergunta) e uniq -cfuncionaria, mas forneceria a saída no formato errado. É por isso que a resposta aceita não usa sorte reformata a saída de uniq -c.
Kusalananda
Obrigado @Aeyd. Eu estava procurando por este comando. Ela ajuda
user11392987
0

Eu usaria python. Hoje em dia, todos os ststem linux têm o python2 instalado.

Adicione cada endereço IP em um dict (matriz associativa) como pares chave = valor, ou seja, {"12.34.56.78": 1, "87.76.43.21": 3}.

Você 'verifica' o endereço IP como uma chave e aumenta o valor em 1. Se você usar defaultdict ("ip"), se a chave não existir, ela será criada com o valor padrão 0. Se a chave existir já, defaultdict não faz nada. O valor é incrementado na próxima linha.

#!/usr/bin/python2

infile = open("file.txt","r")
iplist = {}  # create an empty dict

for line in infile:
    line = line.strip()   # remove newline.
    if line: # if not a blank line.
        iplist.setdefault(line, 0) # check for ip and add with default value of 0
        iplist[line] += 1 # increment

outfile = open("out.txt","w") #open output file

for key in iplist.keys():
    line = "%-15s = %s" % (key, iplist[key])
    print line   # print uf desired.
    outfile.write(line + "\n")

arquivo de saída:

cat out.txt                                                          
27.33.65.2      = 2
58.161.137.7    = 1
121.50.198.5    = 1
184.173.187.1   = 3

Eu sei que você estava procurando uma solução de linha de comando, mas como você pode ver, é uma tela formatada com elegância que levou apenas uma dúzia de linhas. Python é uma excelente ferramenta para administração.

Mike Childers
fonte