【问题标题】:Extracting a subset of records for every entry based on value根据值为每个条目提取记录子集
【发布时间】:2015-12-15 16:23:03
【问题描述】:

我是 unix 新手。我有 tab delim txt 文件如下:

ID     Region Strt End Length
sd_2_1 head   241   930 689
sd_2_1 trunk  16    240 224
sd_2_1 tail    1    15  14

sd_2_1 head    1    1   0
sd_2_1 trunk   2    832 830
sd_2_1 tail   833   930 97

sd_2_1 head   780   930 150
sd_2_1 trunk  663   779 116
sd_2_1 tail   1     662 661

sd_3_1 head  1020   1649 629
sd_3_1 trunk 783    1019 236
sd_3_1 tail   1     782  781

sd_3_1 trunk  1     1470 1469
sd_3_1 tail  1471   1649 178  

sd_4_1 head   2      50   48
sd_4_1 trunk  51     701  650

sd_4_1 head   1      40   38
sd_4_1 trunk  41     101  60
sd_4_1 tail   102    122  20

每个 ID 具有不同条目的多个区域子集(以空格分隔)我想将每个 ID 与其自己的子集进行比较,并仅保留每个 ID 具有最大主干长度的子集。最后我想获得如下文件:

      ID     Region Strt End Length
  sd_2_1      head    1    1   0
  sd_2_1      trunk   2    832 830
  sd_2_1      tail   833   930 97

  sd_3_1      trunk  1     1470 1469
  sd_3_1      tail   1471  1649 178 

  sd_4_1       head   2      50   48
  sd_4_1       trunk  51     701  650

任何帮助将不胜感激。请指导我

【问题讨论】:

  • 为什么在输出中没有sd_3_1head 行? sd_4_1 没有 tail 行?

标签: linux awk grep


【解决方案1】:

awk 来救援!

$ (head -1 file && sed 1d file
    | awk -v RS= '{len=0; 
                   for(i=2;i<=NF;i+=5) 
                      if($i=="trunk") {len=$(i+3); break} 
                   if(len>v[$1]) {v[$1]=len; r[$1]=$0}
                  } 
               END{for(k in r) print r[k]}') 
    | column -t

ID      Region  Strt  End   Length
sd_2_1  head    1     1     0
sd_2_1  trunk   2     832   830
sd_2_1  tail    833   930   97
sd_3_1  trunk   1     1470  1469
sd_3_1  tail    1471  1649  178
sd_4_1  head    2     50    48
sd_4_1  trunk   51    701   650

Subshel​​l就是把header和body分开处理。将记录分隔符设置为段落模式,找到每条记录的相应长度(因为可能缺少某些行,所以复杂性很小)。选择每个键的最大值并在完成后打印。

如果您需要不同 ID 行之间的间距。

... | column -t | awk 'NR<3{p=$1} $1!=p{print "";p=$1} 1'

ID      Region  Strt  End   Length
sd_2_1  head    1     1     0
sd_2_1  trunk   2     832   830
sd_2_1  tail    833   930   97

sd_3_1  trunk   1     1470  1469
sd_3_1  tail    1471  1649  178

sd_4_1  head    2     50    48
sd_4_1  trunk   51    701   650

【讨论】:

    【解决方案2】:

    这里是 perl 版本

    while(<>) { 
        chomp;
        if ($_ =~ /(head|trunk|tail)/) {
            # Parse and store the relevant lines
            ($id, $region, $start, $end, $length) = split;
            $entry{$region} = $_;
            if($region eq "trunk") {
                $trunklength = $length;
            }
        } elsif(defined ($id)) {
            # Check if this is the greatest trunk length
            if($trunklength > $trunklength{$id}) {
                # Clear old values
                $trunklength{$id}= $trunklength;
                undef($trunklength);
                # Store new values
                $trunk{$id} = $entry{"trunk"};
                $head{$id} = $entry{"head"};
                $tail{$id} = $entry{"tail"};
            }
            undef %entry;
        }
    }
    # Print out the answer
    foreach $id (sort (keys(%trunklength))) {
        print "$head{$id}\n" if (defined($head{$id}));
        print "$trunk{$id}\n" if (defined($trunk{$id}));
        print "$tail{$id}\n" if (defined($tail{$id}));
        print "\n";
    }
    

    它首先解析头、开始和尾行,将它们存储在由区域索引的哈希中。存储主干长度。在空行上,将树干长度与存储的 id 的树干长度进行比较。如果它大于之前的 head、trunk 和 length 值,则丢弃并替换为当前版本。这适用于某些值不存在的情况。

    最后循环遍历哈希以打印出所需的值。请注意,perl 对未初始化的变量做了显而易见的事情,因此无需检查 $trunklength{id} 是否未设置。

    【讨论】:

    • 我已经修改了答案,删除了一些不必要的 undef 调用,例如,如果尚未设置新的头条目,$head{$id} = $entry{"head"}; 将用未定义的值覆盖 $head{$id}}
    【解决方案3】:
    1. 没有为 awk 指定输入文件。 awk -F "\t" '{if($5==max)}' ???

    应该是 awk -F "\t" '{if($5==max)}' infile.txt

    或者,如果您打算从以前的管道进程中获取它,我希望您已经使用 xargs 命令替换了 max。

    1. 你想在 grep 中搜索什么?你还没有给出模式

    2. 您的 awk 不打印任何内容。我假设这是一次性要求,并且您已经知道最大值。

      你的命令应该是这样的

    awk '{if($5==max1 || $5==max2 || $5==max3){ print $5 }}' infile.txt | sed 's/ /|/g' | xargs -ipattern grep -C 1 'pattern' &gt;out.txt

    -> 在这里,我使用 sed 从 awk 转换多行输出,并使用 xargs 将模式传递给 grep
    -> 这里,如果 max1,2,3 在整个文件中不是唯一的数字,这个命令就会中断。

    【讨论】:

    • 嗨,感谢您的评论。实际上,我只想保留一个具有最大树干长度的 susbet,并将其与头部和尾部一起打印。例如 sd_2_1 有 3 个具有不同主干长度的子集,我想只打印具有最大主干长度的子集。请指导我
    • 是的,最大 1,2 和 3 分别表示 sd_2_1、sd_3_1 和 sd_4_1 的最大值。因此,它打印 sd_2_1,sd_3_1,sd_4_1 的最高子集
    猜你喜欢
    • 2021-09-23
    • 1970-01-01
    • 2021-08-15
    • 2017-01-22
    • 2021-05-02
    • 2023-02-08
    • 1970-01-01
    • 1970-01-01
    • 2013-02-14
    相关资源
    最近更新 更多