批量提取数千个*.changelog文件中CVE的方案优化问询
问题解答
原方案的可行性
原方案完全可行,但耗时超1小时的核心原因是:shell循环中给每个文件单独调用grep/sort/uniq/awk等外部命令,每次调用都会启动新进程,49000个文件就会产生数万次进程创建/销毁的开销,加上磁盘IO的累积,导致总耗时飙升。
更高效的实现方式
方案1:单进程Awk脚本(最稳定,无并行冲突)
用Awk一次性处理所有文件,全程仅启动一个进程,同时完成单个CVE列表生成和总文件收集,避免反复调用外部工具。
创建提取脚本extract_cves.awk:
BEGIN { # 精确匹配CVE格式:CVE-YYYY-NNNN(YYYY为4位年份,NNNN为4位及以上数字) cve_pattern = /CVE-[0-9]{4}-[0-9]{4,}/ } # 处理每个文件的第一行时,提取包名(去掉.changelog后缀) FNR == 1 { pkg = FILENAME sub(/\.changelog$/, "", pkg) # 用数组存储当前文件的CVE,自动去重 delete current_cves } # 遍历每行,提取所有匹配的CVE cve_pattern { line = $0 # 一行可能包含多个CVE,循环提取 while (match(line, cve_pattern, match_result)) { cve = match_result[0] current_cves[cve] = 1 # 写入总文件临时记录 print pkg "\t" cve >> "all_cves.tmp" # 截断已匹配的部分,继续查找剩余内容 line = substr(line, RSTART + RLENGTH) } } # 当前文件处理完毕,生成单个CVE列表文件 ENDFILE { out_file = pkg ".cve" print "# CVE List for " pkg > out_file for (cve in current_cves) { print cve >> out_file } close(out_file) } # 所有文件处理完成后,对总文件去重排序 END { close("all_cves.tmp") system("sort -u all_cves.tmp > all_cves_pkg_map.txt") system("rm -f all_cves.tmp") }
运行命令:
awk -f extract_cves.awk *.changelog
方案2:并行处理(利用多核,速度更快)
如果机器多核资源充足,用parallel或xargs并行处理多个文件,将总耗时压缩到几分钟级别。
用parallel实现:
# 第一步:并行生成单个文件的CVE列表 parallel --gnu 'grep -o "CVE-[0-9]\{4\}-[0-9]\{4,\}" {} | sort -u > {.}.cve' ::: *.changelog # 第二步:并行提取所有CVE与包名的映射,去重后生成总文件 parallel --gnu 'grep -o "CVE-[0-9]\{4\}-[0-9]\{4,\}" {} | sort -u | awk -v pkg={} '\''BEGIN{sub(/\.changelog$/,"",pkg)} {print pkg "\t" $0}'\''' ::: *.changelog | sort -u > all_cves_pkg_map.txt
注:
--gnu参数适配GNU parallel,若用其他版本可调整;-P N可指定并行进程数(比如-P 16用16核),默认会根据CPU核心数自动调整。
用xargs实现(无parallel时备选):
# 并行生成单个CVE列表 ls *.changelog | xargs -n 1 -P 16 bash -c ' pkg="${1%.changelog}" grep -o "CVE-[0-9]\{4\}-[0-9]\{4,\}" "$1" | sort -u > "$pkg.cve" ' _ # 并行生成总文件映射 ls *.changelog | xargs -n 1 -P 16 bash -c ' pkg="${1%.changelog}" grep -o "CVE-[0-9]\{4\}-[0-9]\{4,\}" "$1" | sort -u | awk -v pkg="$pkg" "{print pkg \"\\t\" \$0}" ' _ | sort -u > all_cves_pkg_map.txt
额外优化建议
- 正则精确匹配:如果有需要,可以把CVE的年份范围限制在合理区间(比如
CVE-20[0-9]{2}-[0-9]{4,}),减少无效匹配。 - 内存文件系统:如果磁盘IO是瓶颈,可将临时文件放在
tmpfs(比如/dev/shm),避免磁盘读写延迟。 - 避免重复扫描:方案1中Awk只扫描一次文件同时完成两类输出,比方案2两次扫描文件更节省IO。
内容的提问来源于stack exchange,提问作者TheLotusMind
相关产品推荐
相关产品推荐

