如何用Bash脚本筛选保留相同序列编号的最大数值行?
问题:保留每个序列编号对应数值最大的行
给定如下输入数据:
# Sequence 6 S TTHTSTAQR 0.687 # Sequence 7 T THTSTAQRS 0.562 # Sequence 11 S TAQRSSKYP 0.960 # Sequence 11 S TAQRSSKYP 0.711 # Sequence 12 S AQRSSKYPT 0.996 # Sequence 12 S AQRSSKYPT 0.684
期望输出为每个序列编号(第三列)保留数值(第五列)最大的行:
# Sequence 6 S TTHTSTAQR 0.687 # Sequence 7 T THTSTAQRS 0.562 # Sequence 11 S TAQRSSKYP 0.960 # Sequence 12 S AQRSSKYPT 0.996
尝试使用awk -F, '!seen[$3]++' tmp > out无法完成需求,该如何解决?
问题分析
你原来的命令有两个核心问题:
- 指定了
-F,用逗号作为分隔符,但你的数据是空格分隔的,导致$3无法正确获取序列编号; !seen[$3]++的逻辑是保留每个键第一次出现的行,而不是数值最大的行,不符合需求。
正确的AWK命令
基础版(输出顺序不保证和原文件一致)
awk '{ key = $3 val = $5 + 0 # 转为数字类型,避免字符串比较误差 if (!(key in max_val) || val > max_val[key]) { max_val[key] = val line[key] = $0 } } END { for (k in line) print line[k] }' tmp > out
保持原顺序版(和示例输出顺序一致)
如果需要保持序列编号在原文件中第一次出现的顺序,用以下命令:
awk '{ key = $3 val = $5 + 0 if (!(key in max_val)) { order[++cnt] = key # 记录首次出现的顺序 } if (val > max_val[key] || !(key in max_val)) { max_val[key] = val line[key] = $0 } } END { for (i=1; i<=cnt; i++) print line[order[i]] }' tmp > out
命令解释
key = $3:以第三列的序列编号作为唯一标识;val = $5 + 0:将第五列的字符串数值转为数字,确保比较时是数值大小而非字符串字典序;- 条件判断:如果当前序列编号未记录过,或者当前行的数值大于已记录的最大值,就更新最大值和对应的整行内容;
- END块:遍历存储的结果,输出最终保留的行(保持顺序版会按原文件中序列首次出现的顺序输出)。
内容的提问来源于stack exchange,提问作者Akash Mondal
相关产品推荐
相关产品推荐

