优化基于grep、awk、cut的大文件邮件数字统计脚本性能
大日志文件下的唯一邮件数字统计优化方案
需求说明
从包含以下格式的日志文件中,统计每个数字对应的唯一邮件数量(需过滤同一邮件的重复记录):
2024-05-08 11:02:58,731 INFO o.a.j.a.J.Some check: Closest Day: Wed, New quantity for email0987@yahoo.com is: 1
期望输出示例:
1 - 6575 emails
2 - 333 emails
现有bash脚本处理几百MB的大文件时速度极慢,需要性能优化。
现有脚本的性能瓶颈
原脚本存在以下低效点:
- 多次调用外部工具(
grep/cut/rev/awk)并通过管道传递数据,产生大量进程切换开销 - 将过滤后的所有数据读入变量再通过
while read循环处理,内存占用高且bash循环本身速度缓慢 - 循环内再次调用
echo/cut等外部工具,进一步放大进程开销
优化方案:单Awk脚本完成所有操作
直接用Awk一次性完成日志过滤、去重、统计,避免多进程和bash循环的开销,这是处理大文本文件最高效的方式之一。
优化后的脚本
#!/bin/bash input_file="$1" awk '/Closest Day:/ { # 直接提取邮件和数字:邮件是倒数第3个字段,数字是倒数第1个字段 email = $(NF-2) number = $NF # 用"邮件-数字"作为复合键去重,确保同一邮件对应同一数字只统计一次 if (!seen[email, number]++) { count[number]++ } } END { # 输出统计结果 for (num in count) { printf "%d - %d emails\n", num, count[num] } }' "$input_file"
优化点说明
- 单进程处理:全程仅启动一个Awk进程,彻底避免多管道和外部工具的进程切换开销
- 内存高效去重:用复合键
email, number记录已出现的组合,确保同一邮件对应同一数字只计数一次 - 原生字段提取:Awk原生支持字段索引,无需
cut/rev等工具拆分字符串 - 无中间数据拷贝:直接读取原文件处理,无需将中间结果存入变量再二次处理
额外性能建议
- 如果日志文件是压缩格式,直接用
zcat/bzcat配合Awk处理,避免先解压再读取:zcat "$input_file.gz" | awk '...' - 若需要按数字排序输出,可将结果管道到
sort -n:awk '...' "$input_file" | sort -n
内容的提问来源于stack exchange,提问作者forkintheass
相关产品推荐
相关产品推荐

