Eu tenho um arquivo de log classificado por endereços IP, quero encontrar o número de ocorrências de cada endereço IP exclusivo. Como posso fazer isso com o bash? Possivelmente listando o número de ocorrências ao lado de um ip, como:
5.135.134.16 count: 5
13.57.220.172: count 30
18.206.226 count:2
e assim por diante.
Aqui está uma amostra do log:
5.135.134.16 - - [23/Mar/2019:08:42:54 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:55 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:55 -0400] "POST /wp-login.php HTTP/1.1" 200 3836 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:55 -0400] "POST /wp-login.php HTTP/1.1" 200 3988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
5.135.134.16 - - [23/Mar/2019:08:42:56 -0400] "POST /xmlrpc.php HTTP/1.1" 200 413 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:05 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:06 -0400] "POST /wp-login.php HTTP/1.1" 200 3985 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:07 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:08 -0400] "POST /wp-login.php HTTP/1.1" 200 3833 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:09 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:11 -0400] "POST /wp-login.php HTTP/1.1" 200 3836 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:12 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:15 -0400] "POST /wp-login.php HTTP/1.1" 200 3837 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.220.172 - - [23/Mar/2019:11:01:17 -0400] "POST /xmlrpc.php HTTP/1.1" 200 413 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
13.57.233.99 - - [23/Mar/2019:04:17:45 -0400] "GET / HTTP/1.1" 200 25160 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36"
18.206.226.75 - - [23/Mar/2019:21:58:07 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "https://www.google.com/url?3a622303df89920683e4421b2cf28977" "Mozilla/5.0 (Windows NT 6.2; rv:33.0) Gecko/20100101 Firefox/33.0"
18.206.226.75 - - [23/Mar/2019:21:58:07 -0400] "POST /wp-login.php HTTP/1.1" 200 3988 "https://www.google.com/url?3a622303df89920683e4421b2cf28977" "Mozilla/5.0 (Windows NT 6.2; rv:33.0) Gecko/20100101 Firefox/33.0"
18.213.10.181 - - [23/Mar/2019:14:45:42 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
18.213.10.181 - - [23/Mar/2019:14:45:42 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
18.213.10.181 - - [23/Mar/2019:14:45:42 -0400] "GET /wp-login.php HTTP/1.1" 200 2988 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0"
command-line
bash
sort
uniq
j0h
fonte
fonte
sort -V
embora eu ache que isso não foi necessário. Enviei os 10 principais abusadores da página de login ao administrador do sistema com recomendações para banir as respectivas sub-redes. por exemplo, um IP atingiu a página de login mais de 9000 vezes. esse IP e sua sub-rede classe D agora estão na lista negra. Tenho certeza de que poderíamos automatizar isso, embora essa seja uma pergunta diferente.Respostas:
Você pode usar
grep
e,uniq
para a lista de endereços, fazer um loop sobre eles egrep
novamente para a contagem:grep -o '^[^ ]*'
gera todos os caracteres do início (^
) até o primeiro espaço de cada linha,uniq
remove linhas repetidas, deixando assim uma lista de endereços IP. Graças à substituição de comando, ofor
loop percorre esta lista imprimindo o IP atualmente processado, seguido de "count" e a contagem. O último é calculado porgrep -c
, que conta o número de linhas com pelo menos uma correspondência.Exemplo de execução
fonte
uniq -c
ouawk
precisam apenas ler o arquivo uma vez,<log grep ...
e nãogrep ... log
?Você pode usar
cut
euniq
ferramentas:Explicação:
cut -d ' ' -f1
: extrair primeiro campo (endereço IP)uniq -c
: relata linhas repetidas e exibe o número de ocorrênciasfonte
sed
, por exemplo,sed -E 's/ *(\S*) *(\S*)/\2 count: \1/'
para obter a saída exatamente como o OP queria.sort file | cut ....
caso não tenha certeza se o arquivo já está classificado.Se você não precisar especificamente do formato de saída especificado, recomendo a resposta já postada com base em
cut
+uniq
Se você realmente precisa do formato de saída fornecido, uma maneira de passagem única no Awk seria
Isso não é ideal quando a entrada já está classificada, pois armazena desnecessariamente todos os IPs na memória - uma maneira melhor, embora mais complicada, de fazê-lo no caso pré-classificado (mais diretamente equivalente a
uniq -c
) seria:Ex.
fonte
Aqui está uma solução possível:
file.log
pelo nome do arquivo real.$(awk '{print $1}' "$IN_FILE" | sort -u)
fornecerá uma lista dos valores exclusivos da primeira coluna.grep -c
contará cada um desses valores no arquivo.fonte
printf
...Alguns Perl:
Essa é a mesma idéia da abordagem awk do Steeldriver , mas no Perl. O
-a
perl faz com que automaticamente divida cada linha de entrada na matriz@F
, cujo primeiro elemento (o IP) é$F[0]
. Portanto,$k{$F[0]}++
criará o hash%k
, cujas chaves são os IPs e cujos valores são o número de vezes que cada IP foi visto. O}{
é funky perlspeak para "faça o resto no final, depois de processar todas as entradas". Portanto, no final, o script irá percorrer as chaves do hash e imprimir a chave atual ($_
) junto com seu valor ($k{$_}
).E, para que as pessoas não pensem que o perl obriga a escrever scripts que pareçam rabiscos enigmáticos, é a mesma coisa de uma forma menos condensada:
fonte
Talvez não seja isso que o OP queira; no entanto, se soubermos que o tamanho do endereço IP será limitado a 15 caracteres, uma maneira mais rápida de exibir as contagens com IPs exclusivos a partir de um grande arquivo de log pode ser obtida usando
uniq
apenas o comando:Opções:
-w N
compara não mais queN
caracteres em linhas-c
prefixará as linhas pelo número de ocorrênciasComo alternativa, para saída formatada exata, eu prefiro
awk
(também deve funcionar para endereços IPV6), ymmv.Observe que
uniq
não detectará linhas repetidas no arquivo de entrada se elas não estiverem adjacentes; portanto, pode ser necessário parasort
o arquivo.fonte
FWIW, Python 3:
Saída:
fonte
Explicação: Pegue o primeiro campo de my.log dividido em hífens
-
e classifique-o.uniq
precisa de entrada classificada.-c
diz para contar ocorrências.fonte