我有一个很大的日志文件,其中包含的所有行都具有相似的格式。它们可能略有不同,但第一个 ] 括号之前的格式始终完全相同。
31.7.112.60 - - [26/Jan/2019:19:32:08 +0330] "GET /product/31284/%D9%85%D8%A7%D8%B4%DB%8C%D9%86-%D9%84%D8%A8%D8%A7%D8%B3%D8%B4%D9%88%DB%8C%DB%8C-%D8%AF%D8%B1%D8%A8-%D8%A7%D8%B2-%D8%AC%D9%84%D9%88-%D8%A8%D9%88%D8%B4-%D9%85%D8%AF%D9%84-BOSCH-WAW28760IR-9Kg HTTP/1.1" 200 41935 "https://www.google.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36" "-"
我需要做两件事:
A)GET /product/XXXXX/
在所有行上搜索该模式(有些行可能没有),其中 XXXXX 可以是可变位数,例如可以是 34213 或 1242 或 1423124,然后按顺序打印前 20 个产品。这应该采用以下格式。
34286,25
33954,18
33952,17
33956,16
33953,16
B) 使用 IP 地址查找并打印每天的唯一用户数。这需要采用以下格式。
22/Jan/2019,3987
26/Jan/2019,5567
答案1
它看起来像一个简单的网络服务器日志。答案就像grep
和 一样简单awk
。
让日志文件的名称为httpd.log
.您可以尝试这个复合命令:
grep -o 'GET \/product\/[^/]*\/' httpd.log |awk 'BEGIN{FS="\/"}{AA[$3]++}END{for(i in AA){print AA[i]" "i}}'|sort -n -r|awk '{print $2","$1}' |head -n20
第一部分隔离重要文本(如果存在),第二部分对产品编号的每次出现进行计数并打印结果,第三部分对列表进行排序,最后两个部分以您指定的形式打印它。
如果您想将每一天分开,您可以在该命令之前加上另一个命令grep
来指定日期。
要过滤 IP 客户端,您可以按照上面所示的示例自行尝试。
答案2
awk -v pat="GET /product/[0-9]*" -F'[[:blank:]:[]' '
BEGIN {PROCINFO["sorted_in"]="@val_num_desc"}
$0 ~ pat {match($0, pat)
A[substr($0, RSTART+13, RLENGTH-13)]++}
!C[$5,$1]++ {D[$5]++}
END {for(i in A){if(++j > 20) break; print i "," A[i]}
for(i in D) print i "," D[i]}
' file
BEGIN {PROCINFO["sorted_in"]="@val_num_desc"}
- 通过数组元素,设置按值降序排序。
$0 ~ pat {match($0, pat);A[substr($0, RSTART+13, RLENGTH-13)]++}
- 创建一个数组,键与产品编号对应,数量计入值中。
!C[$5,$1]++ {D[$5]++}
- 计算唯一值。验证密钥由日期和 IP 组成。
END {for(i in A){ if(++j > 20) break; print i "," A[i]}
- 根据A)点打印数组的前20个键和值。
for(i in D) print i "," D[i]}
- 打印出值和按值排序的键。
如果您需要按最后一点的日期排序,可以将输出重定向到 shell 命令。更改最后一行:
for(i in D) print i "," D[i] | "sort -rt\"/\" -k3,3 -k2,2 -k1,1"}