You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Bash中基于起始/结束值消除文件中的重叠条目?

移除制表符文件中与已保留行重叠的条目

我有一个制表符分隔的文件,条目包含名称、起始位置和结束位置,文件内容如下:

# Name	Start	End
Name1	1	3
Name2	7	9
Name3	5	8
Name4	5	6

我希望删除与之前已保留条目存在重叠的行,本示例的期望输出为:

Name1	1	3
Name2	7	9
Name4	5	6

我目前写了部分Bash脚本:

#!/bin/bash
while IFS=$'\n' read line; do
     # Assign variable names
     name=$(echo $line | cut -f 1)
     start=$(echo $line | cut -f 2)
     end=$(echo $line | cut -f 3)
     # I envision an if statement structured so that:
     # if [ $end < $PreviousStart ] || [ $start > $PreviousEnd ] ; then echo $line >> output.txt
done < file.txt

但这里遇到了问题:我需要检查output.txt里的每一行(也就是原文件中已保留的所有前序行),只有当前行和所有已保留行都不重叠时才打印该行。我觉得Awk应该有更简洁的解决办法,求帮忙。


Awk解决方案

用Awk可以直接在内存中维护已保留的条目,不需要频繁读写文件,效率更高。核心逻辑是遍历每一行,跳过注释行;对当前行的起始/结束位置,和所有已保留条目逐一对比,只要和任意一个重叠就跳过,否则保留该行并记录到内存中。

#!/usr/bin/awk -f
BEGIN { FS = "\t" }
# 跳过注释行
/^#/ { next }
{
    # 标记当前行是否可保留
    keep = 1
    # 遍历所有已保存条目,检查重叠
    for (i in saved) {
        split(saved[i], prev, "\t")
        prev_start = prev[2]
        prev_end = prev[3]
        # 区间重叠判断:当前起始 <= 已存结束 且 当前结束 >= 已存起始
        if ($2 <= prev_end && $3 >= prev_start) {
            keep = 0
            break
        }
    }
    if (keep) {
        print $0
        saved[++count] = $0
    }
}

使用方法

  1. 将上述代码保存为remove_overlaps.awk
  2. 执行命令:awk -f remove_overlaps.awk 你的输入文件名.txt > output.txt

逻辑说明

  • BEGIN { FS = "\t" }:设置字段分隔符为制表符
  • /^#/ { next }:跳过以#开头的注释行
  • 用数组saved存储所有已保留的行,新行进来时逐一对比重叠情况
  • 重叠判断规则:两个区间[a1,a2]和[b1,b2]重叠的条件是a1 <= b2 && a2 >= b1,满足则标记为不保留
  • 仅当当前行与所有已保存行都不重叠时,才打印并保存该行

内容的提问来源于stack exchange,提问作者Dody

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 19:15:57