诗翔的Linux学习之路生物信息学与算法我用 Linux

【shell笔记>文本处理|专项】Linux数据文本处理工

2017-08-24  本文已影响71人  王诗翔

1

file 查看文件编码

wsx@wsx-ubuntu:~$ file regular_express.txt 
regular_express.txt: ASCII text, with CRLF, LF line terminators

常用的大型数据文件一般存为ASCII码形式(像几大基因bank的数据文件),而我们自己认为创建的常为UTF-8,所以有时候认为处理文件需要会碰到把UTF-8编码的字符插入到ASCII码文件里去了。遇到这种问题,我们可以用hexdump -c命令查看出错的地方(手边没有这样的文件,就不举例了)。

sort对文本排序

我们先创建一个bed格式文件来试试这个命令:

wsx@wsx-ubuntu:~$ cat test.bed 
chr1    26  39
chr3    32  47
chr1    40  50
chr1    9   28
chr2    35  54
chr1    10  19
wsx@wsx-ubuntu:~$ sort test.bed 
chr1    10  19
chr1    26  39
chr1    40  50
chr1    9   28
chr2    35  54
chr3    32  47

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

下面是对bed文件最通用的排序命令:

wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed 
chr1    9   28
chr1    10  19
chr1    26  39
chr1    40  50
chr2    35  54
chr3    32  47

基本操作bedtools软件都会先用这个命令对bedtools文件排序。
现在略加解释一下,sort-k选项指定某列的排序方式。而每次使用-k选项都要带上指定列的范围(start, end)。如果只指定一列,就为(start,start)了,像上面命令的-k1,1就是。也许你会觉得-k2,2n很奇怪,这里的n指定程序把第二列当做数值对待。如果不做设定,都是当做字符对待(shell都是这么对待数值数据的)。所以总结其他这一行命令就是对第一列按照字符排序,第二列按照数值排序。

我们可以用-c选项检查一个文件是不是已经按照过某种方式排过序了。

wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed | sort -k1,1 -k2,2 -c
sort:-:2:无序: chr1   10  19
wsx@wsx-ubuntu:~$ echo $?
1
wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed | sort -k1,1 -k2,2n -c
wsx@wsx-ubuntu:~$ echo $?
0

上面可以清楚地看到sort是怎么对待文件的(一般shell返回0表示成功执行)。

wsx@wsx-ubuntu:~$ tsfds
tsfds:未找到命令
wsx@wsx-ubuntu:~$ echo $?
127
wsx@wsx-ubuntu:~$ echo test
test
wsx@wsx-ubuntu:~$ echo $?
0

shell的命令退出状态码表示了该命令执行的完成的某种情况。不同的状态码有不同的含义,具体可以百度查阅(我之前整理的shell笔记应该讲过,可以看看)。

反向排序用-r选项。如果你只想反转一列,可以把它加在-k选项后。

wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2nr test.bed 
chr1    40  50
chr1    26  39
chr1    10  19
chr1    9   28
chr2    35  54
chr3    32  47

现在我给test.bed加一行:

wsx@wsx-ubuntu:~$ cat test.bed 
chr1    26  39
chr3    32  47
chr1    40  50
chr1    9   28
chr2    35  54
chr1    10  19
chr11   22  56

你会发现有点奇怪

wsx@wsx-ubuntu:~$ sort -k1,1 -k2,2n test.bed 
chr1    9   28
chr1    10  19
chr1    26  39
chr1    40  50
chr11   22  56
chr2    35  54
chr3    32  47

怎么chr11chr2前面?其实sort排序的方式有点像查字典。例子中,命令先比较c,然后比较h,然后比较r,接着比较1,自然11会在2前面了。这里可以添加V选项修改。

wsx@wsx-ubuntu:~$ sort -k1,1V -k2,2n test.bed 
chr1    9   28
chr1    10  19
chr1    26  39
chr1    40  50
chr2    35  54
chr3    32  47
chr11   22  56

是不是觉得这样更可观一些?不过通常在处理数据时不做此处理,符合 规范的数据可以让后续处理程序效率更高。

基本掌握sort这些也够用了,它主要为后续处理服务。如果想知道其他的用法,查查吧,同时欢迎发文来交流。

uniq寻找唯一值

首先创建样例文本

wsx@wsx-ubuntu:~$ cat test.letter 
A
A
B
C
B
C
C
C
D
F
D

使用uniq看看

wsx@wsx-ubuntu:~$ uniq test.letter 
A
B
C
B
C
D
F
D

尼玛,怎么不对。它好像只去掉了连续的同一字符。怎么办?想想我们刚学了什么命令?sort不是刚好可以把同样的字符弄到一起去吗,然后再使用uniq,嘿嘿:

wsx@wsx-ubuntu:~$ sort test.letter | uniq
A
B
C
D
F

哟呵,got you。

-c选项计数:

wsx@wsx-ubuntu:~$ sort test.letter | uniq -c
      2 A
      2 B
      4 C
      2 D
      1 F

把结果再排序

wsx@wsx-ubuntu:~$ sort test.letter | uniq -c | sort -rn
      4 C
      2 D
      2 B
      2 A
      1 F

-d选项只输出重复行

wsx@wsx-ubuntu:~$ cat test.letter 
A
A
B
C
B
C
C
C
D
F
D
wsx@wsx-ubuntu:~$ uniq -d test.letter 
A
C
wsx@wsx-ubuntu:~$ sort test.letter | uniq -d
A
B
C
D

使用时需要注意处理不同导致的结果差异。

Join 命令
用来连接文件。
假设现在我们有两个文件:

wsx@wsx-ubuntu:/tmp$ cat example.bed 
chr1    26  39
chr1    32  47
chr3    11  28
chr1    40  49
chr3    16  27
chr1    9   28
chr2    35  53
wsx@wsx-ubuntu:/tmp$ cat example_length.txt 
chr1    53453
chr2    34356
chr3    24356

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

wsx@wsx-ubuntu:/tmp$ sort -k1,1 example.bed > example_sorted.bed
wsx@wsx-ubuntu:/tmp$ sort -c -k1,1 example_length.txt 
wsx@wsx-ubuntu:/tmp$ cat example_sorted.bed 
chr1    26  39
chr1    32  47
chr1    40  49
chr1    9   28
chr2    35  53
chr3    11  28
chr3    16  27
wsx@wsx-ubuntu:/tmp$ join -1 1 -2 1 example_sorted.bed  example_length.txt > example_with_length.txt
wsx@wsx-ubuntu:/tmp$ cat example_with_length.txt 
chr1 26 39 53453
chr1 32 47 53453
chr1 40 49 53453
chr1 9 28 53453
chr2 35 53 34356
chr3 11 28 24356
chr3 16 27 24356

命令基本语法是

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

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

两个文件中,第一列都共有chr1(2)(3)。 如果不一致会出现什么情况呢?

wsx@wsx-ubuntu:/tmp$ join -1 1 -2 1 example_sorted.bed  example_length_alt.txt chr1 26 39 53453
chr1 32 47 53453
chr1 40 49 53453
chr1 9 28 53453
chr2 35 53 34356

如果第二个文件没有chr3join之后也没了!!

我们可以通过-a选项指定哪一个文件可以不遵循配对

wsx@wsx-ubuntu:/tmp$ join -1 1 -2 1 -a 1 example_sorted.bed  example_length_alt.txt 
chr1 26 39 53453
chr1 32 47 53453
chr1 40 49 53453
chr1 9 28 53453
chr2 35 53 34356
chr3 11 28
chr3 16 27

awk
awk是文本处理的一把好手,虽然它不能像pythonR干一些高级复杂的主题工作,但是它具备完整的命令操作和编程体系。

awk是一门语言,我不可能在学习的时候能够逻辑清晰详细地介绍给大家。主要是还通过实例来了解用法,加深认识。手册可以参考http://man.linuxde.net/awk

首先要明白的是,awk按行处理数据。在shell知识里,如果把一个文档看做一张表。那么一行就是一个记录,一列就是一个。可以看出,awk就是按记录处理文本的。

其次是awk的程序结构是

pattern {action}

pattern可以是表达式或者正则表达式。pattern有点像if语句,当它满足时就会执行相应的动作。

另一个awk核心是它用$0表示所有列,$1$2...等等表示对应的列。我们可以很方便地用它进行操作。

wsx@wsx-ubuntu:/tmp$ 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  53
wsx@wsx-ubuntu:/tmp$ awk '{print $1}' example.bed 
chr1
chr1
chr3
chr1
chr3
chr1
chr2
wsx@wsx-ubuntu:/tmp$ awk '{print $2}' example.bed 
26
32
11
40
16
9

print语句就像动作一样输出你操作的结果。

wsx@wsx-ubuntu:/tmp$ awk '{ print $2 "\t" $3}' example.bed 
26  39
32  47
11  28
40  49
16  27
9   28
35  53
wsx@wsx-ubuntu:/tmp$ awk '{ print $2  $3}' example.bed 
2639
3247
1128
4049
1627
928
3553
wsx@wsx-ubuntu:/tmp$ awk '{ print $2 , $3}' example.bed 
26 39
32 47
11 28
40 49
16 27
9 28
35 53

了解上述几个语句的不同。

表示染色体名一般用带chr或者不带chr标志两种方式。当我们要用到这两种时,肯定要让它们能够对应起来,也就是转换。awk命令可以非常方便地添加chr标记。

下面我先把例子文件的chr去掉,然后加上试试。

wsx@wsx-ubuntu:/tmp$ awk '{ print $1}' example.bed
chr1
chr1
chr3
chr1
chr3
chr1
chr2
wsx@wsx-ubuntu:/tmp$ awk '{ print $1}' example.bed | cut -c4 
1
1
3
1
3
1
2
wsx@wsx-ubuntu:/tmp$ awk '{ print $1}' example.bed | cut -c4 | awk '{print "chr"$1}'
chr1
chr1
chr3
chr1
chr3
chr1
chr2

awk作为一门编程语言,它支持各种操作符(运算,逻辑,判断)喔。

wsx@wsx-ubuntu:/tmp$ awk '$3 - $2 >18' example.bed 
chr1    9   28
wsx@wsx-ubuntu:/tmp$ awk '$1 ~/chr1/ && $3 - $2 > 10' example.bed 
chr1    26  39
chr1    32  47
chr1    9   28

# 这里 ~ 符号用来匹配正则表达式

还有awk存在一些变量,像NR表示行号,OFS表示输出分隔符等。

wsx@wsx-ubuntu:/tmp$ awk 'NR >= 3 && NR <= 5' example.bed 
chr3    11  28
chr1    40  49
chr3    16  27

如果我们想把gtf文件转换成为bed格式,可以使用

wsx@wsx-ubuntu:~/Work/research/Promoter_Research$ head -n1000 Homo_sapiens.GRCh37.75.gtf | awk '!/^#/{ print $1 "\t" $4-1 "\t" $5} ' | head -n 3
1   11868   14412
1   11868   14409
1   11868   12227

因为篇幅有限,我不可能输出所有结果,所以只取部分数据做了运算。

上一篇下一篇

猜你喜欢

热点阅读