我的HTTP访问日志文件很大,我正在尝试为特定查询字符串生成每小时计数。显然,正确的解决方案是将所有内容都转储为splunk或graylog或其他内容,但我目前无法一次性完成所有设置。
快捷方式是:
for hour in 0{0..9} {10..23}
do
grep $QUERY $FILE | egrep -c "^\S* $hour:"
# or, alternately
# egrep -c "^\S* $hour:.*$QUERY" $FILE
# not sure which one's better
done
但是这些文件平均需要15-20M行,我真的不想解析每个文件24次。一次性分析文件并计算每个$hour
实例的效率会更高。有什么办法可以做到这一点?
答案 0 :(得分:1)
您可以要求grep用-o
输出每行的匹配部分,然后使用uniq -c
来计数结果:
grep "$QUERY" "$FILE" | grep -o "^\S* [0-2][0-9]:" | sed 's/^\S* //' | uniq -c
这里的sed
命令仅保留两位数的小时和冒号,如果需要,您还可以使用另一个sed表达式将其删除。
注意事项:此解决方案可与GNU grep和GNU sed一起使用,并且在没有日志条目的情况下,不会产生任何输出,而不是“ 0”。感谢@EdMorton在注释中指出了这些问题,以及上面的答案中已解决的其他问题。
答案 1 :(得分:1)
假设时间戳显示在2位数小时之前有一个空格,然后是一个冒号
digraph "a" {
a -> b
}
这将创建24个文件。
需要3 arg形式的match()GNU awk
答案 2 :(得分:0)
这可能正是您真正需要的,使用GNU awk作为match()的第三个arg,并假设您的输入看起来像什么,QUERY变量可能包含什么以及输出应该是什么样子:>
awk -v query="$QUERY" '
match($0, " ([0-9][0-9]):.*"query, a) { cnt[a[1]+0]++ }
END {
for (hr=0; hr<=23; hr++) {
printf "%02d = %d\n", hr, cnt[hr]
}
}
' "$FILE"
对于未导出的shell变量,请不要真正使用大写字母-参见Correct Bash and shell script variable capitalization。