通过指定多个字段来删除重复行,保留第二个排序行

时间:2015-12-02 03:49:07

标签: sorting unix awk bioinformatics uniq

我有一个看起来像的文件:

chr1          mireap  precursor  6405246   6405544   .  -  .  ID=xxx-m0444;Count=3;mfe=-61.00
chr1          mireap  mature-5p  6405511   6405534   .  -  .  ID=xxx-m0444-5p;Parent=xxx-m044
chr1          mireap  precursor  6482110   6482198   .  +  .  ID=xxx-m0417;Count=105;mfe=-45.
chr1          mireap  mature-5p  6482123   6482143   .  +  .  ID=xxx-m0417-5p;Parent=xxx-m041
chr1          mireap  mature-3p  6482168   6482188   .  +  .  ID=xxx-m0417-3p;Parent=xxx-m041
chr1          mireap  mature-3p  6482168   6482188   .  +  .  Name=vvi-miR395g;ID=xxx-m0417-3

为澄清而大量编辑

当字段1,4和5在第二行重复时,我想在字段9的开头保留包含“名称”信息的重复行。字段9始终以“ID”或“名称”开头。我想删除字段9以“ID”开头的重复行。

例如,所需的输出如下所示:

chr1          mireap  precursor  6405246   6405544   .  -  .  ID=xxx-m0444;Count=3;mfe=-61.00
chr1          mireap  mature-5p  6405511   6405534   .  -  .  ID=xxx-m0444-5p;Parent=xxx-m044
chr1          mireap  precursor  6482110   6482198   .  +  .  ID=xxx-m0417;Count=105;mfe=-45.
chr1          mireap  mature-5p  6482123   6482143   .  +  .  ID=xxx-m0417-5p;Parent=xxx-m041
chr1          mireap  mature-3p  6482168   6482188   .  +  .  Name=vvi-miR395g;ID=xxx-m0417-3

根据'man sort',-u仅输出“同等运行”的第一行。我把它解释为......好吧,如果我只是反向排序而不是使用-u,那么将保留包含“Name”的行。

sort -k1,1 -k4,4n -rk5,5n file # Correctly sorts the file and the name line appears first relative to its duplicate.

sort -u -k1,1 -k4,4n -k5,5n -rk9,9 file # Runs, but still eliminates the "Name"-containing line anyway.

我也想过做这样的事情:

sort -k1,1 -k4,4n -rk5,5n file | awk '!x[$1,$4,%5]++' FS="\t" # but haven't gotten it to work quite yet and this still wouldn't retain the desired duplicate line...

想法?

3 个答案:

答案 0 :(得分:4)

$ cat tst.awk
{ key = $1 FS $4 FS $5; isNameLine = ($9~/^Name=/ ? 1 : 0) }
NR==FNR { if (isNameLine) hasNameLine[key]; next }
isNameLine || !(key in hasNameLine)

$ awk -f tst.awk file file
chr1          mireap  precursor  6405246   6405544   .  -  .  ID=xxx-m0444;Count=3;mfe=-61.00
chr1          mireap  mature-5p  6405511   6405534   .  -  .  ID=xxx-m0444-5p;Parent=xxx-m044
chr1          mireap  precursor  6482110   6482198   .  +  .  ID=xxx-m0417;Count=105;mfe=-45.
chr1          mireap  mature-5p  6482123   6482143   .  +  .  ID=xxx-m0417-5p;Parent=xxx-m041
chr1          mireap  mature-3p  6482168   6482188   .  +  .  Name=vvi-miR395g;ID=xxx-m0417-3

答案 1 :(得分:0)

我的要求并不完全清楚, 但这里有一个简短的脚本,希望建议一个合适的实现。它的写作清晰而不是简洁。

首先让我们来定义" family"表示具有相同的一组线 [$ 1,$ 4,$ 5]价值。假设你总是想保留至少一个 "名称="一个家庭中的行,全局排序确实有意义 否则内存要求可能过高。

所以,让我们从您提出的那种开始,然后是awk 程序,您可能希望进一步调整,具体取决于 您的要求的详细信息和有关的详细信息 构造输入文件时遵循的约定:

        Dictionary<string, int> ab = new Dictionary<string, int>
        {
            {"a", 1},
            {"b", 0},
            {"c", 3},
            {"d", 0},
            {"e", 5}
        };

        foreach(var pair in ab)
        {
            if(pair.Value != 0)
                Console.WriteLine(pair.Key + "=" + pair.Value);
        }

答案 2 :(得分:0)

使用sort并首先按awk惯用法选择,并根据“名称”的词汇顺序&gt; “ID”。

$ sort -k1,1 -k4,5 -k9,9r file | awk '!a[$1 FS $4 FS $5]++'

chr1          mireap  precursor  6405246   6405544   .  -  .  ID=xxx-m0444;Count=3;mfe=-61.00
chr1          mireap  mature-5p  6405511   6405534   .  -  .  ID=xxx-m0444-5p;Parent=xxx-m044
chr1          mireap  precursor  6482110   6482198   .  +  .  ID=xxx-m0417;Count=105;mfe=-45.
chr1          mireap  mature-5p  6482123   6482143   .  +  .  ID=xxx-m0417-5p;Parent=xxx-m041
chr1          mireap  mature-3p  6482168   6482188   .  +  .  Name=vvi-miR395g;ID=xxx-m0417-3

更新: 基于评论它看起来像$ 9的ID部分也应该是关键。由于没有测试数据,请验证

$ sort -k1,1 -k4,5 -k9,9r file 
     | awk '{match($9,/(ID=[^;]+;)/,m)} 
            !a[$1 FS $4 FS $5 FS m[1]]++'