前面我们学习了基本的Unix表格文本数据的处理命令(grep
, cut
, sort
, uniq
等),但是在更加复杂的情况下这些命令使用起来就力不从心了。对表格数据进行更加复杂的操作可以使用awk
脚本语言,这里介绍一下它的用法。
基本用法
awk
的用法由两部分组成
record。
awk
专门处理表格文本,它将输入的文本的每一行会当作一个record,智能地将整行内容赋给变量$0
,第一列赋给$1
,第二列赋给$2
,以此类推。pattern { action }
的模式进行匹配与操作。pattern为判断条件,类似其它语言if语句,满足pattern的行进行action操作;如果pattern被省略的话对每一行都进行action操作;如果action被省略的话会展示所有满足pattern的行。
action
以example.bed
文件为例,使用awk
打印文本所有内容:
$ awk '{print $0}' example.bed
chr1 26 39
chr1 32 47
chr3 11 28
chr1 40 49
chr3 16 27
chr1 9 28
chr2 35 54
chr1 10 19
print $0
操作可以省略$0
接着,我们可以使用awk
模仿cut
的操作(结果与cut -f2,3 example.bed
一致):
$ awk '{print $2 "\t" $3}' example.bed
26 39
32 47
11 28
40 49
16 27
9 28
35 54
10 19
pattern
下面展示pattern的使用,比如说我们想要查看feature长度大于18的行:
$ awk '$3 - $2 > 18' example.bed
chr1 9 28
chr2 35 54
awk
支持基本的数学运算例如+,-,*,/,%(取余)。
pattern支持逻辑操作(见表1):
例如我们过滤得到1号染色体特征长度大于10的行:
$ awk '$1~/chr1/ $3 - $2 > 10' example.bed
chr1 26 39
chr1 32 47
chr1 40 49
chr1 9 28
chr1 10 19
组合pattern与action
通过组合pattern与action我们可以对特定的行进行操作,例如在染色体2或者3所在行添加特征长度信息:
$ awk '$1 ~ /chr[23]/ {print $0 "\t" ($3 - $2)}' example.bed
chr3 11 28 17
chr3 16 27 11
chr2 35 54 19
总结:以上我们已经学习了awk
的基本用法,通过awk我们可以达到下面的两个基本目的:
- 数据过滤
- 添加新的列
awk进阶操作
awk
有两个比较方便的进阶操作:
1. BEGIN与END
awk
的pattern可以设为BEGIN
或END
,代表在所有action开始之前与结束之后进行的操作,可以利用BEGIN
进行变量的初始化,END
进行总结。例如我们计算所有行特征长度的平均值。
$ awk 'BEGIN {s = 0}; {s+=($3 - $2)} END {print "mean: " s/NR}' example.bed
mean: 14
NR为内置变量,代表行数。
awk
还有一些其它的内置函数见表2
关联向量
awk
支持关联向量(可以像Python的字典一样存储变量),例如我们利用这点统计Mus_musculus.GRCm38.75_chr1.gtf
文件(如下)中Lypla1基因不同的特征的数目:
$ grep -v "^#" Mus_musculus.GRCm38.75_chr1.gtf | head -n3
1 pseudogene gene 3054233 3054733 . + . gene_id "ENSMUSG00000090025"; gene_name "Gm16088"; gene_source "havana"; gene_biotype "pseudogene";
1 unprocessed_pseudogene transcript 3054233 3054733 . + . gene_id "ENSMUSG00000090025"; transcript_id "ENSMUST00000160944"; gene_name "Gm16088"; gene_source "havana"; gene_biotype "pseudogene"; transcript_name "Gm16088-001"; transcript_source "havana"; tag "cds_end_NF"; tag "cds_start_NF"; tag "mRNA_end_NF"; tag "mRNA_start_NF";
1 unprocessed_pseudogene exon 3054233 3054733 . + . gene_id "ENSMUSG00000090025"; transcript_id "ENSMUST00000160944"; exon_number "1"; gene_name "Gm16088"; gene_source "havana"; gene_biotype "pseudogene"; transcript_name "Gm16088-001"; transcript_source "havana"; exon_id "ENSMUSE00000848981"; tag "cds_end_NF"; tag "cds_start_NF"; tag "mRNA_end_NF"; tag "mRNA_start_NF";
命令为:
$ awk '/Lypla1/ {feature[$3] += 1}; \
END { \
for (k in feature) \
print k "\t" feature[k]\
}' Mus_musculus.GRCm38.75_chr1.gtf
exon 69
CDS 56
UTR 24
gene 1
start_codon 5
stop_codon 5
transcript 9
上面操作与下面的Unix命令操作得到的结果一致,不过使用awk
可以方便地进行更加复杂的逻辑操作(例如通过&&添加),这是Unix命令无法比拟的。
$ grep -v "^#" Mus_musculus.GRCm38.75_chr1.gtf | cut -f3 | sort | uniq -c
25901 CDS
7588 UTR
36128 exon
2027 gene
2290 start_codon
2299 stop_codon
4993 transcript
最后,虽然awk
针对文本每行的处理非常方便,但是涉及到多行操作将变得复杂,这种情况建议优先使用R或者Python。