如何改写低效shell脚本 实现批量匹配大文件分存结果的需求
优化方案说明
原有脚本的性能瓶颈非常明确:如果参考文件有N条pattern,就会对两个5GB大文件各做N次全量扫描,再加上每次循环内调用echo、cut、grep、sed、awk产生的大量子进程开销,执行效率会指数级下降。
最优方案是仅对两个大文件各扫描1次,全程用awk完成所有逻辑,完全不需要shell循环:
实现脚本
#!/bin/bash dir="./output/" mkdir -p "$dir" awk ' # 第一步先读取参考文件,把pattern和对应object存进哈希表 NR == FNR { if (FNR == 1) next # 跳过表头 obj[$2] = $1 next } # 第二步处理大文件,滚动缓存行用于匹配后取上下行 { prev3 = prev2 prev2 = prev1 prev1 = $0 # 匹配当前行是否以任意pattern开头,忽略大小写 for (p in obj) { if (tolower(prev2) ~ "^" tolower(p)) { # 匹配成功就输出:上1行、匹配行、下2行,写入对应object的文件 print prev3 >> ("'"$dir"'" obj[p] ".txt") print prev2 >> ("'"$dir"'" obj[p] ".txt") print prev1 >> ("'"$dir"'" obj[p] ".txt") print $0 >> ("'"$dir"'" obj[p] ".txt") close("'"$dir"'" obj[p] ".txt") # 避免打开文件数超过系统限制 break } } } ' reference_file.csv a_very_big_file.txt another_very_big_file.txt
方案优势
- 两个5GB大文件仅各被读取1次,IO开销直接降低到原有方案的1/N,N为参考文件的pattern数量
- 没有任何shell循环和子进程开销,所有匹配、提取、写文件逻辑都在单个awk进程内完成
- 自动实现原有逻辑的忽略大小写匹配、剔除空行、剔除grep分隔符的效果,不需要额外调用sed/awk/grep
注意事项
如果参考文件的pattern数量极多(超过10万条),可以提前对pattern做前缀排序优化匹配速度,绝大多数场景下上述脚本直接可用,性能远高于原有循环写法。
内容的提问来源于stack exchange,提问作者another_rando
相关产品推荐
相关产品推荐

