新加入这个社区。我在 bash 脚本中执行此操作。我的问题几乎概括了我正在寻找的内容。我有一个日志文件,其中包含一堆 IP 地址和其他数据。我想计算每个特定日期的唯一 IP 地址的数量并将其存储到变量中。关于如何使用 grep 和 awk 来做到这一点有什么想法吗?
日期格式为 11/Feb/2020(这是一个示例)。
日志文件中的示例文本:
57.34.156.99 - - [11/Feb/2020:04:32:18 +0330]
43.21.223.33 - - [11/Feb/2020:09:13:05 +0330]
87.44.212.82 - - [14/Mar/2020:06:22:01 +0330]
43.21.223.33 - - [11/Feb/2020:11:05:32 +0330]
上述输出:
11/Feb/2020:2
14/Mar/2020:1
如您所见,我只想对重复的 IP 地址进行一次计数。
任何帮助表示赞赏。如果我应该提供更多信息,请告诉我。
答案1
这是问题示例格式的答案,但一般来说,其他日志格式的过程类似(通常日期是 ISO 格式并且在第一个字段中)。要将任务与格式分开,首先仅查看 IP 和日期:
> awk '{print substr($4,2,10), $1}' file
11/Feb/202 57.34.156.99
11/Feb/202 43.21.223.33
14/Mar/202 87.44.212.82
11/Feb/202 43.21.223.33
我们可以使用一个关联数组,其中哈希值将是日期和 ip,并且它会随着“date-ip”的出现而增加。另一个数组用于计算实际结果,其中哈希将仅是日期。
awk '{d = substr($4,2,10)} !seen[d FS $1]++ {cnt[d]++}
END {for (x in cnt) print x ":" cnt[x]}
' file | sort -t ":" -rnk2
输出:
11/Feb/202:2
14/Mar/202:1
cnt
请注意,数组的顺序未定义,因此通过 ip 计数通过END
管道传输日期很有用。sort
或者你可以使用GNU awk 数组排序函数。中的变量
awk
不是隐式定义的,最初为零或空字符串,因此对于任何新的“date-ip”集,!seen[date-ip]++
都将为 true,之后它会增加。所以下次我们遇到这个“date-ip”时,它会是假的,我们不会增加cnt[date]
。
在每行仅提取“date-ip”之后,使用sort
and进行相同的操作:uniq
> awk '{print substr($4,2,10), $1}' file | sort -u | awk '{print $1}' | uniq -c
2 11/Feb/202
1 14/Mar/202
在这里,我们在排序时删除重复项sort -u
(因为稍后uniq
需要对其输入进行排序),仅保留第一个字段(日期),最后uniq -c
打印每个唯一日期的计数。这对于不太熟悉的人来说更具可读性awk
。为了演示该过程,您可以打印该命令的每个步骤以查看其进展情况。