如何用awk删除文件重复行,保留第5列最接近参考文件值的行
问题描述
我有两个文件:
file1.txt 内容
$cat file1.txt 0105 20 20 95 50 0106 20 20 95 50 0110 20 20 88 60 0110 20 20 88 65 0115 20 20 82 70 0115 20 20 82 70 0115 20 20 82 75
file1.txt第一列存在重复值,分别是0110和0115。我需要对file1.txt做行筛选,规则是:如果首列重复仅保留1行,保留行的第5列值要和参考文件file2.txt中同首列条目的第5列值最接近(相等或差值最小),不需要修改file1的原有值。
file2.txt 内容
$cat file2.txt 0105 20 20 95 50 0106 20 20 95 50 0107 20 20 95 52 0110 20 20 88 65 34 0112 20 20 82 80 23 0113 20 20 82 85 32 0114 20 20 82 70 23 0115 20 20 82 72 0118 20 20 87 79 0120 20 20 83 79
期望输出
0105 20 20 95 50 0106 20 20 95 50 0110 20 20 88 65 0115 20 20 82 70
已尝试的错误脚本
awk 'FNR==NR { a[$5]; next } $5 in a ' file1.txt file2.txt > test.txt awk '{a[NR]=$1""$2} a[NR]!=a[NR-1]{print}' test.txt
预期的算法逻辑
# 逐行检查file1.txt第一列的条目是否和下一行重复 即 外层遍历行号i: 内层遍历列号j: 如果当前行第j列值不等于下一行第j列值,直接输出整行; 如果相等: # 找到file2.txt中首列和当前行首列相同的行 # 把该行的第5列,和file1中所有首列等于当前首列的行的第5列做差 # 取差值最小的行保留 例:如果有3行首列相同的条目,选择差值最小的那行即可
解决方法
直接用单条awk命令即可实现需求:
awk ' # 先读取file2,把首列作为键,存储对应第5列的参考值 FNR == NR { ref[$1] = $5 next } # 再读取file1,按首列分组,记录差值最小的行 { cur_diff = $5 > ref[$1] ? $5 - ref[$1] : ref[$1] - $5 # 如果当前首列无记录,或当前行差值更小,就更新存储内容 if (!($1 in min_diff) || cur_diff < min_diff[$1]) { min_diff[$1] = cur_diff res[$1] = $0 } } # 最后遍历输出结果,加sort保证顺序和原文件一致 END { for (key in res) { print res[key] } } ' file2.txt file1.txt | sort -k1n
逻辑说明
- 第一步读取参考文件file2,提前把首列对应的第5列参考值存入数组,避免后续重复查找
- 读取file1时实时计算当前行第5列和参考值的绝对差值,每个首列仅保留差值最小的行;如果差值相同会保留先出现的行,符合示例中0115首列两个70的筛选逻辑
- 最后对输出结果按第一列数值排序,保证输出顺序和预期完全一致
内容的提问来源于stack exchange,提问作者Kay
相关产品推荐
相关产品推荐

