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

Remove duplicate lines by specifying more than one field, keep second sorted line

我有一个如下所示的文件:

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 的开头保留包含 "Name" 信息的重复行。字段 9 始终以 "ID" 或 "Name"。我想删除字段 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只输出"an equal run"的第一行。我将其解释为...好吧,如果我只是简单地反向排序而不是使用 -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[,,%5]++' FS="\t" # but haven't gotten it to work quite yet and this still wouldn't retain the desired duplicate line...

想法?

$ cat tst.awk
{ key =  FS  FS ; isNameLine = (~/^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

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

首先让我们定义"family"表示一组具有相同 [$1,$4,$5] 价值。假设您总是想保留至少一个 一个家族中的 "Name=" 行,全局排序确实有意义,因为 否则内存要求可能会令人望而却步。

那么让我们从您建议的排序开始,然后是 awk 程序,您可能希望根据 您的要求的详细信息和有关的其他详细信息 输入文件的构造遵循的约定:

sort -k1,1 -k4,4n -k5,5n -rk9,9 |\
  awk '{ seen[,,]++ }
        ~ /^Name=/ {print; next}
       seen[,,] > 1 { next; }
       { print }' 

使用 sort 并首先根据 awk 习语选择,并取决于 "Name" > "ID".

的词汇顺序
$ sort -k1,1 -k4,5 -k9,9r file | awk '!a[ FS  FS ]++'

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(,/(ID=[^;]+;)/,m)} 
            !a[ FS  FS  FS m[1]]++'