awk用关联数组以ip为下标计数,支持按字段或正则提取ipv4/ipv6,可排序、过滤(如≥10次或排除127/10网段),并兼容带括号的ipv6格式。

直接用 awk 的关联数组就能高效完成 IP 去重和计数,核心是把 IP 当作数组下标,每出现一次就自增对应值。
提取 IP 并累计计数
假设日志每行含标准 IPv4 地址(如 Nginx 或 Apache 的 access.log),常见格式为:192.168.1.100 - - [10/Jan/2024:08:30:12 +0000] "GET / HTTP/1.1" 200 1234。可用空格分隔,取第一个字段:
-
基础命令:
awk '{ip[$1]++} END {for (i in ip) print i, ip[i]}' access.log -
$1是首字段(通常即客户端 IP);ip[$1]++自动创建键并累加;END块遍历输出 - 若 IP 不在第一列(如 syslog 格式),需用正则提取:
awk 'match($0, /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) {ip[substr($0,RSTART,RLENGTH)]++} END {for (i in ip) print i, ip[i]}' logfile
按出现次数倒序排列
默认遍历顺序不确定,要排序需借助 shell 管道:
awk '{ip[$1]++} END {for (i in ip) print ip[i], i}' access.log | sort -nr-
print ip[i], i把次数放前,方便用sort -n按数值排序;-r表示降序 - 若只想要 Top 10:
| head -10
过滤高频或低频 IP
可在 END 块中加条件判断,避免后期管道筛选:
- 只输出出现 ≥ 10 次的 IP:
awk '{ip[$1]++} END {for (i in ip) if (ip[i] >= 10) print i, ip[i]}' access.log - 排除本地地址(如 127.0.0.1、10.x.x.x):
awk '$1 !~ /^127\.|^10\./ {ip[$1]++} END {for (i in ip) print i, ip[i]}' access.log
处理 IPv6 或混合格式日志
IPv6 地址含冒号且可能被方括号包裹(如 [2001:db8::1]),需调整匹配逻辑:
- 用更健壮的正则提取任意 IP:
awk '{match($0, /\b([0-9]{1,3}\.){3}[0-9]{1,3}\b|\b([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b\[([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\]/); if (RSTART) {ip[substr($0,RSTART,RLENGTH)]++}} END {for (i in ip) print i, ip[i]}' logfile - 实际中建议先清洗:对带方括号的 IPv6 去括号再统计,例如
gsub(/\[/,"",$1); gsub(/\]/,"",$1)配合字段定位











