帮酷LOGO
  • 显示原文与译文双语对照的内容


问题:

我有一个按IP地址排序的日志文件,我想找到每个唯一IP地址的出现次数。 我如何在bash中实现这个? 可能列出ip旁边出现的次数,例如:

5.135.134.16 count: 5
13.57.220.172: count 30
18.206.226 count:2

等等。

以下是日志的示例:

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"

回答 1:

对于地址列表,可以使用 grepuniq,并再次对它的进行循环,以便计算:

for i in $(<log grep -o '^[^ ]*' | uniq); do
 printf '%s count %dn'"$i" $(<log grep -c"$i")
done

grep -o '^[^ ]*' 从开头(^)输出每个字符直到每行的第一个空格,uniq删除重复的行,从而为您留下IP地址列表。 由于命令替换,for循环遍历此列表,打印当前处理的IP,然后是“count ”和计数。 后者由 grep -c 计算,它计算至少有一个匹配的行的数目。

运行示例

$ for i in $(<log grep -o '^[^ ]*'|uniq);do printf '%s count %dn'"$i" $(<log grep -c"$i");done
5.135.134.16 count 5
13.57.220.172 count 9
13.57.233.99 count 1
18.206.226.75 count 2
18.213.10.181 count 3

回答 2:

你可以使用 cutuniq 工具:

cut -d ' ' -f1 test.txt | uniq -c
 5 5.135.134.16
 9 13.57.220.172
 1 13.57.233.99
 2 18.206.226.75
 3 18.213.10.181

说明:

  • cut -d ' ' -f1 :提取第一个字段( ip地址)
  • uniq -c: 报告重复的行并显示出现的次数

回答 3:

如果不需要特定的输出格式,那么我建议已经发布了基于 cut + uniq的应答。

如果你真的需要给定的输出格式,那么在Awk中执行它的单程方式就是

awk '{c[$1]++} END{for(i in c) print i,"count:" c[i]}' log

当输入已经排序时,这有点不理想,因为它不必要地将所有IP存储到内存中 - 在预先排序的情况下(更直接等同于uniq -c)这样做的更好但更复杂的方法是:

awk '
 NR==1 {last=$1} 
 $1!= last {print last,"count:" c[last]; last = $1} 
 {c[$1]++} 
 END {print last,"count:" c[last]}
'

示例

$ awk 'NR==1 {last=$1} $1!= last {print last,"count:" c[last]; last = $1} {c[$1]++} END{print last,"count:" c[last]}' log
5.135.134.16 count: 5
13.57.220.172 count: 9
13.57.233.99 count: 1
18.206.226.75 count: 2
18.213.10.181 count: 3

回答 4:

以下是一个可能的解决方案:

IN_FILE="file.log"
for IP in $(awk '{print $1}'"$IN_FILE" | sort -u)
do
 echo -en"${IP}tcount:"
 grep -c"$IP""$IN_FILE"
done
  • file.log 替换为实际文件名。
  • 命令替换表达式 $(awk '{print $1}'"$IN_FILE" | sort -u) 将提供第一列的唯一值的列表。
  • 然后 grep -c 将在文件中计算每个值。
$ IN_FILE="file.log"; for IP in $(awk '{print $1}'"$IN_FILE" | sort -u); do echo -en"${IP}tcount:"; grep -c"$IP""$IN_FILE"; done
13.57.220.172 count: 9
13.57.233.99 count: 1
18.206.226.75 count: 2
18.213.10.181 count: 3
5.135.134.16 count: 5

回答 5:

一些 Perl:

$ perl -lae '$k{$F[0]}++; }{ print"$_ count: $k{$_}" for keys(%k)' log 
13.57.233.99 count: 1
18.206.226.75 count: 2
13.57.220.172 count: 9
5.135.134.16 count: 5
18.213.10.181 count: 3

这与steeldriver方法的 awk相同,但是在Perl中。-a 使perl自动将每个输入行分割成 array @F,后者的第一个元素( IP ) 是 $F[0] 。 因此,$k{$F[0]}++ 将创建散列 %k,它的密钥为 IP,它的值是每个IP被查看的次数。 }{ 是"在处理所有输入之后,在最末尾执行其余操作"的时髦 perlspeak 。 最后,脚本将迭代哈希的键并打印当前密钥( $_ ) 及它的值( $k{$_} ) 。

因这里,人们不认为perl强制你编写看起来像隐含的图案的脚本,这是一样的:

perl -e '
 while (my $line=<STDIN>){
 @fields = split(//, $line);
 $ip = $fields[0];
 $counts{$ip}++;
 }
 foreach $ip (keys(%counts)){
 print"$ip count: $counts{$ip}n"
 }' <log

回答 6:

可以能这不是操作需要;但如果我们知道IP地址长度将限制为 15个字符,可以以使用 uniq 命令

$ uniq -w 15 -c log
5 5.135.134.16 - - [23/Mar/2019:08:42:54 -0400].. .
9 13.57.220.172 - - [23/Mar/2019:11:01:05 -0400].. .
1 13.57.233.99 - - [23/Mar/2019:04:17:45 -0400].. .
2 18.206.226.75 - - [23/Mar/2019:21:58:07 -0400].. .
3 18.213.10.181 - - [23/Mar/2019:14:45:42 -0400].. .

选项:

-w N 在行中不多于 N 字符

-c 将按出现的次数对行进行前缀

另外,对于精确格式化的输出,我更喜欢 awk ( 也应用于IPV6地址),ymmv 。

$ awk 'NF { print $1 }' log | sort -h | uniq -c | awk '{printf"%s count: %dn", $2,$1 }'
5.135.134.16 count: 5
13.57.220.172 count: 9
13.57.233.99 count: 1
18.206.226.75 count: 2
18.213.10.181 count: 3

注意,如果 uniq 不是相邻的,则不会检测到输入文件中的重复行,因这里可以能需要对文件进行 sort


回答 7:

FWIW,python 3:

from collections import Counter
with open('sample.log') as file:
 counts = Counter(line.split()[0] for line in file)
for ip_address, count in counts.items():
 print('%-15s count: %d' % (ip_address, count))

输出:

13.57.233.99 count: 1
18.213.10.181 count: 3
5.135.134.16 count: 5
18.206.226.75 count: 2
13.57.220.172 count: 9

回答 8:
cut -f1 -d- my.log | sort | uniq -c

说明:在破折号上分割my.log分割的第一个字段 - 并对其进行排序。 uniq 需要排序的输入 -c 告诉它计数发生。





Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语