提升bash脚本性能:批量处理CSV文件提取多时间范围数据
脚本优化方案
原脚本性能瓶颈
- 单文件重复读取:每个CSV被sed遍历5次,磁盘IO开销直接放大5倍,数十万文件场景下这是最大性能损耗点
- 重复计算时间阈值:循环内每次执行5次date命令,完全可以提前全局计算一次
- 无提前终止逻辑:sed会遍历整个文件,哪怕目标数据已经全部输出
核心优化实现
用awk单次遍历单个CSV即可同时生成5个目标文件,同时新增提前终止逻辑,避免无效读取:
# 提前创建输出目录,避免报错 mkdir -p temp_data_store # 全局预计算所有时间阈值,仅执行一次 d2y=$(date -d "2 year ago" '+%Y-%m') d1y=$(date -d "1 year ago" '+%Y-%m') d6m=$(date -d "6 month ago" '+%Y-%m') d3m=$(date -d "3 month ago" '+%Y-%m') d1m=$(date -d "1 month ago" '+%Y-%m') # 循环处理所有CSV,单文件仅遍历一次 for k in *.csv; do awk -v d2y="$d2y" -v d1y="$d1y" -v d6m="$d6m" -v d3m="$d3m" -v d1m="$d1m" \ -v outdir="temp_data_store/" -v fname="$k" ' BEGIN { f2y = 0; f1y = 0; f6m = 0; f3m = 0; f1m = 0 out2y = outdir fname ".2years.csv" out1y = outdir fname ".1year.csv" out6m = outdir fname ".6months.csv" out3m = outdir fname ".3months.csv" out1m = outdir fname ".1month.csv" } # 表头统一写入所有输出文件 NR == 1 { print $0 > out2y; print $0 > out1y; print $0 > out6m; print $0 > out3m; print $0 > out1m next } { # 提取当前行的YYYY-MM格式日期,日期在行首用substr($0,1,7),日期在第一列直接写cur=$1即可 cur = substr($0, 1, 7) # 匹配到对应时间阈值后开启对应文件的写入标记 if (!f2y && cur >= d2y) f2y = 1 if (f2y) print $0 > out2y if (!f1y && cur >= d1y) f1y = 1 if (f1y) print $0 > out1y if (!f6m && cur >= d6m) f6m = 1 if (f6m) print $0 > out6m if (!f3m && cur >= d3m) f3m = 1 if (f3m) print $0 > out3m if (!f1m && cur >= d1m) f1m = 1 if (f1m) print $0 > out1m # 所有标记都开启后说明所有时间段的数据已经全部输出,直接终止当前文件读取 if (f2y && f1y && f6m && f3m && f1m) exit }' "$k" done
进阶并行优化
如果服务器CPU核心充足,可以用GNU Parallel并行处理文件,进一步压缩耗时:
# 并行数-j可根据CPU核心数调整,建议设为核心数的1~2倍 ls *.csv | parallel -j 16 ' awk -v d2y='"$d2y"' -v d1y='"$d1y"' -v d6m='"$d6m"' -v d3m='"$d3m"' -v d1m='"$d1m"' \ -v outdir="temp_data_store/" -v fname="{}" '\'' BEGIN { f2y = 0; f1y = 0; f6m = 0; f3m = 0; f1m = 0 out2y = outdir fname ".2years.csv" out1y = outdir fname ".1year.csv" out6m = outdir fname ".6months.csv" out3m = outdir fname ".3months.csv" out1m = outdir fname ".1month.csv" } NR == 1 { print $0 > out2y; print $0 > out1y; print $0 > out6m; print $0 > out3m; print $0 > out1m next } { cur = substr($0, 1, 7) if (!f2y && cur >= d2y) f2y = 1 if (f2y) print $0 > out2y if (!f1y && cur >= d1y) f1y = 1 if (f1y) print $0 > out1y if (!f6m && cur >= d6m) f6m = 1 if (f6m) print $0 > out6m if (!f3m && cur >= d3m) f3m = 1 if (f3m) print $0 > out3m if (!f1m && cur >= d1m) f1m = 1 if (f1m) print $0 > out1m if (f2y && f1y && f6m && f3m && f1m) exit }'\'' {} '
预期性能提升
仅替换为awk单遍历逻辑,性能即可达到原脚本的5~10倍,加上并行优化后,耗时可随核心数线性下降,完全满足高频运行需求。
内容的提问来源于stack exchange,提问作者usert4jju7
相关产品推荐
相关产品推荐

