根据值为每个条目提取记录子集

时间:2015-12-14 15:31:32

标签: linux awk grep

我是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

任何帮助都将受到高度赞赏。请指导我

3 个答案:

答案 0 :(得分:3)

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是将标题与正文分开进行处理。将记录分隔符设置为段落模式,找到每条记录的相应长度(因为某些行可能缺失,所以几乎没有复杂性)。选择每个键的最大值并在完成后打印。

如果您需要不同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

答案 1 :(得分:1)

这是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}是否未设置为例。

答案 2 :(得分:0)

  1. 没有为awk指定输入文件。 awk -F&#34; \ t&#34; &#39; {如果($ ==您最大)}&#39; ???
  2. 应该是awk -F&#34; \ t&#34; &#39; {如果($ ==您最大)}&#39; infile.txt

    或者如果你想从以前的管道进程中获取它,我希望你用xargs命令代替max。

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

    2. 你的awk没有打印任何东西。我假设这是一次性要求,并且您已经知道最大值,。

      您的命令应该类似于

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

      - &GT;这里我使用sed转换来自awk的多行输出,并使用xargs将模式传递给grep
      - &gt;这里,如果max1,2,3不是整个文件中的唯一数字,则此命令将中断。