linux学习笔记4-文本操作(3)

awk命令

awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。

awk 按行处理数据。
在shell知识里,如果把一个文档看做一张表。那么一行就是一个记录,一列就是一个域。
awk 核心是它用 0 表示所有列, 1 , 2 ...等等表示对应的列。我们可以很方便地用它进行操作,r语言中的提取列也是类似的操作。

$ awk '{print $0}' test.txt
gene    11869   14412
transcript  11869   14409
exon    11869   12227
exon    12613   12721
exon    13221   14409
transcript  11872   14412
exon    11872   12227
exon    12613   12721
exon    13225   14412
transcript  11874   14409

$ awk '{print $1}' test.txt
gene
transcript
exon
exon
exon
transcript
exon
exon
exon
transcript

awk的程序结构是

pattern {action}

pattern可以是表达式或者正则表达式,有点像 if 语句,当它满足时就会执行相应的动作。
awk作为一门编程语言,它支持各种操作符(运算,逻辑,判断)。
awk 存在一些变量,像 NR 表示行号, OFS 表示输出分隔符等。

$ head -n1000 Homo_sapiens.GRCh37.75.gtf | awk '!/^#/ ' | head -n 3
1   pseudogene  gene    11869   14412   .   +   .   gene_id "ENSG00000223972"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene";
1   processed_transcript    transcript  11869   14409   .   +   .   gene_id "ENSG00000223972"; transcript_id "ENST00000456328"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene"; transcript_name "DDX11L1-002"; transcript_source "havana";
1   processed_transcript    exon    11869   12227   .   +   .   gene_id "ENSG00000223972"; transcript_id "ENST00000456328"; exon_number "1"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene"; transcript_name "DDX11L1-002"; transcript_source "havana"; exon_id "ENSE00002234944";
# 如果我们想把 gtf 文件转换成为 bed 格式,可以使用
$ head -n1000 Homo_sapiens.GRCh37.75.gtf | awk '!/^#/{ print $1 "\t" $4-2 "\t" $5} ' | head -n 3
1   11867   14412
1   11867   14409
1   11867   12227

其余操作参考http://man.linuxde.net/awk

sort命令

sort命令是在Linux里非常有用,它将文件进行排序,并将排序结果标准输出。sort命令既可以从特定的文件,也可以从stdin中获取输入。

$ cat test.txt
gene    11869   14412
transcript  11869   14409
exon    11869   12227
exon    12613   12721
exon    13221   14409
transcript  11872   14412
exon    11872   12227
exon    12613   12721
exon    13225   14412
transcript  11874   14409
$ sort test.txt
exon    11869   12227
exon    11872   12227
exon    12613   12721
exon    12613   12721
exon    13221   14409
exon    13225   14412
gene    11869   14412
transcript  11869   14409
transcript  11872   14412
transcript  11874   14409

可以明显看到文本按照第一列进行了排序。
sort 默认用空格或tab键作为列分隔符。如果我们用其他形式的分隔符,需要用 -t 选项指定。

$ sort -k2,2n test.txt
exon    11869   12227
gene    11869   14412
transcript  11869   14409
exon    11872   12227
transcript  11872   14412
transcript  11874   14409
exon    12613   12721
exon    12613   12721
exon    13221   14409
exon    13225   14412

sort 用 -k 选项指定某列的排序方式,要带上指定列的范围(start, end)。如果只指定一列,就为(start,start)了。
-k2,2n 里的 n 指定程序把第二列当做数值对待。如果不做设定,都是当做字符对待(shell都是这么对待数值数据的)。所以总结其他这一行命令就是对第一列按照字符排序,第二列按照数值排序。
反向排序用 -r 选项。如果你只想反转一列,可以把它加在 -k 选项后。
可以用 -c 选项检查一个文件是不是已经按照过某种方式排过序了。

$ sort -k2,2nr test.txt
exon    13225   14412
exon    13221   14409
exon    12613   12721
exon    12613   12721
transcript  11874   14409
exon    11872   12227
transcript  11872   14412
exon    11869   12227
gene    11869   14412
transcript  11869   14409
$ cat test.txt
gene    11869   14412
transcript  11869   14409
exon    11869   12227
exon    12613   12721
exon    13221   14409
transcript  11872   14412
exon    11872   12227
exon    12613   12721
exon    13225   14412
transcript  11874   14409

$ awk '{print $1}' test.txt > test5.txt
$ cat test5.txt
gene
transcript
exon
exon
exon
transcript
exon
exon
exon
transcript

$ uniq test5.txt
gene
transcript
exon
transcript
exon
transcript

加 -c 选项计数:

$ sort test5.txt | uniq -c
      6 exon
      1 gene
      3 transcript

再把结果排序

$ sort test5.txt | uniq -c | sort -rn 
      6 exon
      3 transcript
      1 gene

-d 选项只输出重复行

$ sort test5.txt | uniq -d
exon
transcript

join命令

join命令用来将两个文件中,制定栏位内容相同的行连接起来。找出两个文件中,指定栏位内容相同的行,并加以合并,再输出到标准输出设备。
语法

join(选项)(参数)

选项

-a<1或2>:除了显示原来的输出内容之外,还显示指令文件中没有相同栏位的行;
-e<字符串>:若[文件1]与[文件2]中找不到指定的栏位,则在输出中填入选项中的字符串;
-i或--ignore-case:比较栏位内容时,忽略大小写的差异;
-o<格式>:按照指定的格式来显示结果;
-t<字符>:使用栏位的分割字符;
-v<1或2>:更-a相同,但是只显示文件中没有相同栏位的行;
-1<栏位>:连接[文件1]指定的栏位;
-2<栏位>:连接[文件2]指定的栏位。

我想把第二个文件添加到第一个文件对应的第四列。 我们首先要给文件排序(使用 join 前
必须做),然后使用 join 命令。

$ sort -k2,2nr test.txt 
exon    13225   14412
exon    13221   14409
exon    12613   12721
exon    12613   12721
transcript  11874   14409
exon    11872   12227
transcript  11872   14412
exon    11869   12227
gene    11869   14412
transcript  11869   14409
$ sort -k2,2nr test.txt > test_1.txt
$ cat test_1.txt
exon    13225   14412
exon    13221   14409
exon    12613   12721
exon    12613   12721
transcript  11874   14409
exon    11872   12227
transcript  11872   14412
exon    11869   12227
gene    11869   14412
transcript  11869   14409
$ cat test_2.txt
exon    13225   14412
exon    13221   14409
exon    12613   12721
exon    12613   12721
exon    11872   12227
exon    11869   12227

命令基本语法是

join -1 <file_1_field> -2 <file_2_field> <file_1> <file_2>

既然名字叫 join ,就是两者必须有共同之处,通过共同的支点将两者连为一体。
-1 和 -2 选项后接参数分别指定了这个支点,也就是连接的域(列)。
比如例子中,都是两个文件的第一列。
两个文件中,第2列都共有 相同数值 。 如不一致会出现什么情况呢?

$ join -1 2 -2 2 test_1.txt test_2.txt > test_3.txt
join: test_1.txt:6: is not sorted: exon 11872   12227
$ cat test_3.txt
13225 exon 14412 exon 14412
13221 exon 14409 exon 14409
12613 exon 12721 exon 12721
12613 exon 12721 exon 12721
12613 exon 12721 exon 12721
12613 exon 12721 exon 12721

事实是test_2.tx没有transcript、gene, join 之后也没了!
我们可以通过 -a 选项指定哪一个文件可以不遵循配对,下面指定test_1.txt可以不遵循配对。

$ join -1 2 -2 2 -a 1 test_1.txt test_2.txt > test_3.txt
join: test_1.txt:6: is not sorted: exon 11872   12227
$ cat test_3.txt
13225 exon 14412 exon 14412
13221 exon 14409 exon 14409
12613 exon 12721 exon 12721
12613 exon 12721 exon 12721
12613 exon 12721 exon 12721
12613 exon 12721 exon 12721
11874 transcript 14409
11872 exon 12227
11872 transcript 14412
11869 exon 12227
11869 gene 14412
11869 transcript 14409

wc 命令

wc 命令默认依次输出单词数、行数、总字符数

wc(选项)(参数)
-c或--bytes或——chars:只显示Bytes数;
-l或——lines:只显示列数;
-w或——words:只显示字数。</pre>

如果存在空行,空行会被计数。可以使用 grep 命令实现非空行计数 grep -c "[^ \n\t]" some_data.bed
输出文件列数:

-F指定分隔符,此处假定是table键分隔,默认空格键
awk -F "\t" '{print NF; exit}' some_data.bed
怎么去除注释的元数据行呢?怎么计数非注释行行数呢?
可以使用 tail 结合 awk.

$ head -n 6 Homo_sapiens.GRCh37.75.gtf
#!genome-build GRCh37.p13
#!genome-version GRCh37
#!genome-date 2009-02
#!genome-build-accession NCBI:GCA_000001405.14
#!genebuild-last-updated 2013-09
1   pseudogene  gene    11869   14412   .   +   .   gene_id "ENSG00000223972"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene";
$ tail -n +6 Homo_sapiens.GRCh37.75.gtf | head -n 1
1   pseudogene  gene    11869   14412   .   +   .   gene_id "ENSG00000223972"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene";
#注意+后面的数字,表示从第6行开始才是需要的显示文件。

一种更为通用的方法是 grep 结合 awk 命令

$ grep -v "^#" Homo_sapiens.GRCh37.75.gtf | head -n 1
1   pseudogene  gene    11869   14412   .   +   .   gene_id "ENSG00000223972"; gene_name "DDX11L1"; gene_source "ensembl_havana"; gene_biotype "pseudogene";

参考文件:

【1】Jimmy老师Linux基础知识(链接在下面)
【2】linux命令行文本操作一文就够
https://mp.weixin.qq.com/s__biz=MzAxMDkxODM1Ng%3D%3D&idx=1&mid=2247485539&sn=cbb02d48ea5bb90ee5bdf35d501ee428
【3】 生物信息学常见的数据下载,包括基因组,gtf,bed,注释 http://www.biotrainee.com/thread-857-1-1.html
【4】 (13)Hg19基因组的一些分析-生信菜鸟团博客2周年精选文章集 https://cloud.tencent.com/developer/article/1054518
【5】 Linux命令大全

生信技能树公益视频合辑:学习顺序是linux,r,软件安装,geo,小技巧,ngs组学!
B站链接:https://m.bilibili.com/space/338686099
YouTube链接:https://m.youtube.com/channel/UC67sImqK7V8tSWHMG8azIVA/playlists
生信工程师入门最佳指南:https://mp.weixin.qq.com/s/vaX4ttaLIa19MefD86WfUA
学徒培养:https://mp.weixin.qq.com/s/3jw3_PgZXYd7FomxEMxFmw
生信技能树 - 简书 https://www.jianshu.com/u/d645f768d2d5

猜你喜欢

转载自blog.csdn.net/weixin_33721427/article/details/86990718