如何在Shell脚本中提取两个CSV文件的差异数据
Shell提取两个CSV文件差异数据的实现方案
先提前统一两个文件的基础格式,避免匹配异常:如果是Windows导出的CSV先执行dos2unix 文件.csv转换换行符,提前过滤掉无意义的末尾空行可以用grep -v '^$' 原文件.csv > 处理后文件.csv。
场景1:不要求保留原行顺序,整行完全匹配找差异
优先用comm命令,处理大文件速度最快,注意comm要求输入内容是排序状态:
- 如果CSV没有表头,直接执行以下命令即可:
# 先对两个文件排序生成临时文件 sort a.csv > a_sorted.tmp sort b.csv > b_sorted.tmp # 提取所有差异:输出结果中无缩进的是a.csv独有内容,带一个制表符缩进的是b.csv独有内容 comm -3 a_sorted.tmp b_sorted.tmp > diff_raw.csv # 如果不需要缩进区分,直接把所有差异行平铺输出 comm -3 a_sorted.tmp b_sorted.tmp | sed 's/^\t//' > diff_result.csv # 删除临时文件 rm *.tmp
- 如果CSV带表头,先单独提取表头,跳过表头再对比,最后拼接结果:
# 取第一个文件的表头作为结果文件表头 head -n 1 a.csv > diff_result.csv # 跳过两个文件的第一行表头,排序后对比 tail -n +2 a.csv | sort > a_no_header.tmp tail -n +2 b.csv | sort > b_no_header.tmp comm -3 a_no_header.tmp b_no_header.tmp | sed 's/^\t//' >> diff_result.csv rm *.tmp
场景2:需要保留原文件的行顺序找差异
用awk实现,不需要提前排序,执行效率也很高:
# 提取所有只在a.csv中存在、b.csv中不存在的行,保留a.csv里的原有顺序 awk 'NR==FNR{record[$0]=1;next} !record[$0]' b.csv a.csv > only_in_a.csv # 提取所有只在b.csv中存在、a.csv中不存在的行,保留b.csv里的原有顺序 awk 'NR==FNR{record[$0]=1;next} !record[$0]' a.csv b.csv > only_in_b.csv # 合并两个结果就是全量差异 cat only_in_a.csv only_in_b.csv > all_diff.csv
如果不需要整行匹配,只按指定字段判断是否为同一条数据(比如按第1列的用户ID匹配),只需要修改awk里的数组键即可,比如按第1列(逗号分隔)匹配a独有的行:
awk -F ',' 'NR==FNR{record[$1]=1;next} !record[$1]' b.csv a.csv > only_in_a_by_id.csv
特殊场景注意
如果你的CSV里存在引号包裹的带逗号字段(比如"张三,运营部",1001这种格式),不要用上面简单的逗号分隔逻辑,会出现字段拆分错误,建议用专门的CSV处理工具(比如csvkit)做对比,避免匹配结果出错。
内容的提问来源于stack exchange,提问作者N I R M A L
相关产品推荐
相关产品推荐

