通过指定多个字段删除重复行,保留第二个排序行
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]]++'
我有一个如下所示的文件:
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]]++'