Bash自定义排序:按ID分组,将指定行移至组首
按第一列分组并将匹配行移至组首的解决方案
这问题用awk处理最合适不过了,毕竟它天生擅长按字段分组和文本匹配。我给你写个脚本,完美贴合你的需求:
BEGIN { FS = "\t" } # 请根据实际文件分隔符调整,空格分隔改为 FS="[[:space:]]+" prev_id = "" { # 提取第一列ID的最后一段(下划线分隔)作为匹配关键词 n = split($1, id_parts, "_") match_key = id_parts[n] # 判断第二列是否包含这个匹配关键词 if (index($2, match_key) > 0) { match_lines[$1] = match_lines[$1] $0 "\n" } else { non_match_lines[$1] = non_match_lines[$1] $0 "\n" } # 当分组切换时,输出前一组的内容(先匹配行,后不匹配行) if ($1 != prev_id && prev_id != "") { printf "%s%s", match_lines[prev_id], non_match_lines[prev_id] delete match_lines[prev_id] delete non_match_lines[prev_id] } prev_id = $1 } END { # 处理最后一组数据 printf "%s%s", match_lines[prev_id], non_match_lines[prev_id] }
脚本工作原理
- 字段分隔符设置:BEGIN块里的
FS要根据你文件的实际分隔符调整——如果是制表符分隔就用"\t",如果是空格分隔就改成"[[:space:]]+"(匹配任意数量空格/制表符)。 - 分组跟踪:用
prev_id变量记录当前处理的第一列ID,实现按ID分组。 - 匹配逻辑:拆分第一列ID,提取最后一个下划线后的片段(比如你的示例里
aac(3)-IIa_1_X51534会提取出X51534),然后检查第二列是否包含这个片段。如果你的匹配规则不同,直接修改这里的判断逻辑就行——比如要判断第二列包含整个第一列,就改成index($2, $1) > 0。 - 输出顺序:每个分组先输出所有匹配的行,再输出不匹配的行,保证匹配行在组首。
使用方法
- 把上面的脚本保存为
reorder_lines.awk。 - 运行命令:
awk -f reorder_lines.awk 你的输入文件名 > 输出文件名。
这个脚本利用awk的数组特性分组存储行,处理效率很高,哪怕你的文件很大也能轻松应对~
内容的提问来源于stack exchange,提问作者Jess
相关产品推荐
相关产品推荐

