如何在Bash中对比两文本文件并补全缺失字段生成新文件
Bash处理CSV文件补全缺失字段方案
嘿,我来帮你搞定这个两个CSV文件补全缺失内容的问题!先理清楚你的需求,再看看现有尝试的问题,最后给你一个可行的脚本和详细解释。
你的文件内容
A.txt
cat A.txt 10,1,1,"ABC" 10,1,2,"S1" 10,1,2,"ABC" 10,1,3,"baba" 10,2,1,"S2" 10,2,1,"asd" 10,2,2,"S3" 10,2,2,"dkkd" 10,2,3,"ABC"
B.txt
cat B.txt 10,1,1,"ABC1" 10,1,2,"S1" 10,1,2,"ABC" 10,1,3,"baba" 10,2,1,"asd" 10,2,2,"S3" 10,2,2,"dkkd" 10,2,4,"bokaj"
你尝试的MWE
#!/bin/bash cut -d ',' -f1,2,3 A.txt > A1.txt cut -d ',' -f1,2,3 B.txt > B1.txt ## Command to print contents which are in B1.txt but not in A1.txt A=`awk 'NR==FNR{a[$0];next} !($0 in a)' A1.txt B1.txt` echo $A,'" "' >> A.txt sort A.txt ## Command to print contents which are in A1.txt but not in B1.txt B=`awk 'NR==FNR{a[$0];next} !($0 in a)' B1.txt A1.txt` echo $B,'" "' >> B.txt sort B.txt
现有尝试的问题
- 缺失多条记录的处理:比如A.txt里
10,2,1有两条记录,你的方法只处理了键的存在与否,没考虑同一个键下的多条值 - 追加方式错误:
echo $A,'" "'会把所有缺失的键合并成一行,而不是每条单独生成一行 - 未保存结果:
sort A.txt只是输出到终端,没有写入新文件;而且直接修改原文件也容易导致数据混乱
可行解决方案脚本
这个脚本用awk来处理,它非常适合这种按键分组、匹配多行记录的文本任务:
#!/bin/bash # 清理之前的结果文件(可选,避免重复运行时内容叠加) rm -f A1.txt B1.txt # 核心处理逻辑:收集键值对,补全缺失内容 awk -F',' ' { # 提取前3个字段作为唯一键 key = $1 "," $2 "," $3 # 提取第4个字段作为值 val = $4 # 根据文件名分别存储到对应数组 if (FILENAME == "A.txt") { a[key][count_a[key]++] = val } else { b[key][count_b[key]++] = val } # 记录所有出现过的键 all_keys[key] = 1 } END { # 生成补全后的A1.txt for (key in all_keys) { # 获取A和B中该键对应的记录数量 len_a = count_a[key] ? count_a[key] : 0 len_b = count_b[key] ? count_b[key] : 0 # 取最大数量,保证两个文件行数一致 max_len = (len_a > len_b) ? len_a : len_b # 循环补全每一行 for (i=0; i<max_len; i++) { # 如果A中有对应位置的值就用它,否则补空字符串 current_val = (i < len_a) ? a[key][i] : "\" \"" print key "," current_val >> "A1.txt" } } # 生成补全后的B1.txt for (key in all_keys) { len_a = count_a[key] ? count_a[key] : 0 len_b = count_b[key] ? count_b[key] : 0 max_len = (len_a > len_b) ? len_a : len_b for (i=0; i<max_len; i++) { current_val = (i < len_b) ? b[key][i] : "\" \"" print key "," current_val >> "B1.txt" } } } ' A.txt B.txt # 对结果文件排序,保证两个文件的行顺序完全一致 sort A1.txt -o A1.txt sort B1.txt -o B1.txt
脚本详细解释
1. 键值收集阶段
- 用
-F','指定逗号为字段分隔符 - 把每行前3个字段拼接成
key(比如10,1,1),第4个字段作为val(比如"ABC") - 用二维数组
a和b分别存储A.txt和B.txt中每个键对应的所有值;count_a和count_b记录每个键下的记录数 all_keys数组记录所有出现过的键,确保不会遗漏任何一个键
2. 补全文件阶段
- 遍历所有键,计算该键在两个文件中的最大记录数
max_len(保证两个文件对应键的行数一致) - 循环
max_len次:如果当前文件有对应位置的值就用它,否则用" "补全,写入结果文件
3. 排序阶段
- 最后用
sort命令对两个结果文件排序,确保它们的行顺序完全一致,方便后续对比或处理
最终结果验证
运行脚本后,你会得到行数一致的A1.txt和B1.txt:
A1.txt
10,1,1,"ABC" 10,1,2,"S1" 10,1,2,"ABC" 10,1,3,"baba" 10,2,1,"S2" 10,2,1,"asd" 10,2,2,"S3" 10,2,2,"dkkd" 10,2,3,"ABC" 10,2,4," "
B1.txt
10,1,1,"ABC1" 10,1,2,"S1" 10,1,2,"ABC" 10,1,3,"baba" 10,2,1," " 10,2,1,"asd" 10,2,2,"S3" 10,2,2,"dkkd" 10,2,3," " 10,2,4,"bokaj"
内容的提问来源于stack exchange,提问作者Biki Teron
相关产品推荐
相关产品推荐

