Bash:按标记分组的日志文件中使用的字节数

Bash:按标记分组的日志文件中使用的字节数

假设一个几 GB 且有几百万行的大型日志文件,其中每行都包含一个令牌,用于标识生成该行的用户帐户。

所有标记都具有相同的长度,并且可以在每个日志行内的位置找到。

目标是找出每个帐户记录的字节数。

实现此目的的一种方法是分多个步骤,如下所示:

awk -F "|" '{ print $5 }' trace.log | sort | uniq | xargs -l sh -c 'echo -n $0 && grep "$0" trace.log | wc -c'

其中 awk 提取标记(第 5 个条目通过 '|' 进行标记),sort | uniq 提取文件中出现的唯一标记列表,最后 xargs greps 并计算字节数。

现在它可以工作了,但是效率非常低,因为同一个(巨大的)文件被 grep 了 X 次。

有没有更智能的方法通过 shell 命令实现相同的目的?(更智能的意思是更快并且不消耗大量的 RAM 或临时存储,比如在 RAM 中对整个文件进行排序或将其排序到 tmp 文件)。

答案1

尝试:

awk -F "|" '{ a[$5]+=1+length($0) } END{for (name in a) print name,a[name]}' trace.log

例子

让我们考虑这个测试文件:

$ cat trace.log
1|2|3|4|jerry|6
a|b|c|d|phil|f
1|2|3|4|jerry|6

原始命令产生以下输出:

$ awk -F "|" '{ print $5 }' trace.log | sort | uniq | xargs -l sh -c 'echo -n $0 && grep "$0" trace.log | wc -c'
jerry32
phil15

建议的命令仅循环遍历文件一次,产生以下输出:

$ awk -F "|" '{ a[$5]+=1+length($0) } END{for (name in a) print name,a[name]}' trace.log
jerry 32
phil 15

怎么运行的

  • -F "|"

    这将设置输入的字段分隔符。

  • a[$5]+=1+length($0)

    对于每一行,我们将该行的长度添加到a该行用户名下的关联数组中存储的计数中。

    该数量length($0)不包括行尾的换行符。因此,我们在此基础上加一以说明\n

  • END{for (name in a) print name,a[name]}

    我们读完文件一次后,就打印出总数。

相关内容