复习:
Linux文本处理三剑客之awk
按照指定的列去除重复
上述命令的意思是,如果第一列有重复,则保留最先出现的值;如果没有重复,则保留该值。($1
表示第一列,如果想对第二列进行处理,则$2
,以此类推)如:
$ cat example.txt MA_100472g0010 MA_100472 91.67 492 0 1 1 451 19718 21193 0.0 813 MA_100472g0010 MA_100472 82.84 134 14 2 446 572 22465 22860 6e-59 226 MA_8348g0030 MA_10059887 38.44 666 369 16 20 655 4782 2818 1e-101 350 MA_99999g0010 MA_10430467 51.37 146 69 1 1 146 20468 20899 3e-30 125 MA_99999g0010 MA_36290 47.06 136 72 0 1 136 8905 8498 3e-23 10
|
去除重复后:
$ awk '!a[$1]++' example.txt MA_100472g0010 MA_100472 91.67 492 0 1 1 451 19718 21193 0.0 813 MA_8348g0030 MA_10059887 38.44 666 369 16 20 655 4782 2818 1e-101 350 MA_99999g0010 MA_10430467 51.37 146 69 1 1 146 20468 20899 3e-30 125
|
如果事先通过排序,将想要的最优值排在前面,则去除重后,得到的即为最优值。
拆分文件
如有以下文件:
$ head TAIR10_GFF3.gff 1 TAIR10 gene 3631 5899 . + . ID=AT1G01010;Note=protein_coding_gene;Name=AT1G01010 1 TAIR10 mRNA 3631 5899 . + . ID=AT1G01010.1;Parent=AT1G01010;Name=AT1G01010.1;Index=1 1 TAIR10 exon 3631 3913 . + . Parent=AT1G01010.1 1 TAIR10 five_prime_UTR 3631 3759 . + . Parent=AT1G01010.1 1 TAIR10 CDS 3760 3913 . + 0 Parent=AT1G01010.1,AT1G01010.1-Protein; 1 TAIR10 exon 3996 4276 . + . Parent=AT1G01010.1 1 TAIR10 CDS 3996 4276 . + 2 Parent=AT1G01010.1,AT1G01010.1-Protein; 1 TAIR10 exon 4486 4605 . + . Parent=AT1G01010.1 1 TAIR10 CDS 4486 4605 . + 0 Parent=AT1G01010.1,AT1G01010.1-Protein; 1 TAIR10 exon 4706 5095 . + . Parent=AT1G01010.1
|
按第三列进行拆分:
awk '{print > $3}' TAIR10_GFF3.gff
|
得到:
$ ls -lh total 72M -rw-rw-r-- 1 liuhui liuhui 15M Aug 5 13:58 CDS -rw-rw-r-- 1 liuhui liuhui 12M Aug 5 13:58 exon -rw-rw-r-- 1 liuhui liuhui 2.2M Aug 5 13:58 five_prime_UTR -rw-rw-r-- 1 liuhui liuhui 2.5M Aug 5 13:58 gene -rw-rw-r-- 1 liuhui liuhui 3.2M Aug 5 13:58 mRNA -rw-rw-r-- 1 liuhui liuhui 36M Aug 5 13:58 TAIR10_GFF3.gff -rw-rw-r-- 1 liuhui liuhui 2.0M Aug 5 13:58 three_prime_UTR $ head -n 3 CDS 1 TAIR10 CDS 3760 3913 . + 0 Parent=AT1G01010.1,AT1G01010.1-Protein; 1 TAIR10 CDS 3996 4276 . + 2 Parent=AT1G01010.1,AT1G01010.1-Protein; 1 TAIR10 CDS 4486 4605 . + 0 Parent=AT1G01010.1,AT1G01010.1-Protein; $ head -n 3 exon 1 TAIR10 exon 3631 3913 . + . Parent=AT1G01010.1 1 TAIR10 exon 3996 4276 . + . Parent=AT1G01010.1 1 TAIR10 exon 4486 4605 . + . Parent=AT1G01010.1
|
行-列转化
1. 一行变多行
需要将如下格式转换成“一个基因号对应一个 GO 号”
$ cat pta_go.txt PITA_000018514-RA GO:0003700,GO:0005634,GO:0006355,GO:0043565 PITA_000094612-RA GO:0005618,GO:0006073,GO:0016762,GO:0048046 PITA_000087838-RA GO:0008762,GO:0016491,GO:0050660,GO:0055114 PITA_000082501-RA GO:0003824,GO:0008152 PITA_000063616-RA GO:0030247
|
可以这样:
$ awk '{gsub(/,/, "\n"$1"\t") $ cat pta_go.annot PITA_000018514-RA GO:0003700 PITA_000018514-RA GO:0005634 PITA_000018514-RA GO:0006355 PITA_000018514-RA GO:0043565 PITA_000094612-RA GO:0005618 PITA_000094612-RA GO:0006073 PITA_000094612-RA GO:0016762 PITA_000094612-RA GO:0048046 PITA_000087838-RA GO:0008762 PITA_000087838-RA GO:0016491 PITA_000087838-RA GO:0050660 PITA_000087838-RA GO:0055114 PITA_000082501-RA GO:0003824 PITA_000082501-RA GO:0008152 PITA_000063616-RA GO:0030247
|
原理就是将所有的逗号 ,
依次替换成 "\n"$1"\t"
;而不含有逗号的则照常打印出来。
2. 多行变一行
$ awk '{a[$1]=($1 in a ? a[$1]","$2 : $0)} END{for (k in a) print a[k]}' pta_go.annot PITA_000018514-RA GO:0003700,GO:0005634,GO:0006355,GO:0043565 PITA_000082501-RA GO:0003824,GO:0008152 PITA_000094612-RA GO:0005618,GO:0006073,GO:0016762,GO:0048046 PITA_000063616-RA GO:0030247 PITA_000087838-RA GO:0008762,GO:0016491,GO:0050660,GO:0055114
|
即将文件 pta_go.annot
的格式转成文件 pta_go.txt
的格式
这里用到了三目运算符?:
,?
代表是
,而:
代表否
。如:
$ awk 'BEGIN{a="b";print a=="b" ? "ok" : "err"}' ok $ awk 'BEGIN{a="b";print a=="c" ? "ok" : "err"}' err
|
所以,语句
a[$1]=($1 in a ? a[$1]","$2 : $0)
|
的含义是:$1
如果是第一次出现,将$0
存入数组a
中,数组的下标是$1
;如果$1
在数组 a
中,表明其出现两次或以上时,则将a[$1]
(代表之前的 $0
)和 $2
存入数组 a
中(即更新数组)。
当该语句执行完毕后,执行 END
语句块,将数组a
的结果打印出来。