题目是这样的:
统计SRR1039510_1.fastq.gz碱基总数 1575000
由于上一题已经列出了该文件中所有的序列
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | head
TGGGAGGCTGAGGCAGGAGAATCACTTAAACCTGGGAGGCAGAGGTTACAGTGAGCCGAGATT
AAAGAAGGCGACAGTGAGAAGGAGTCCGAGAAGAGTGATGGAGACCCAATAGTCGATCCTGAG
CTGCTGGGCCCCAAGGTCCTCCTGGTCCCAGTGGTGAAGAAGGAAAGAGAGGCCCTAATGGGG
CTTGGCTGCAGCCATCCCGCTTAGCCTGCCTCACCCACACCCGTGTGGTACCTTCAGCCCTGG
TGAGACAGGTAATTCAGTATAGTAGATTAATATTTTTAATATATATTTTCCCTTAAGATTTCC
ATTTCTCAGTGTAGAAATCATGTCTTCTTAATTGCTGAACCTTACTGCAAAAACTTGTGATGT
ATCAAGAATACCAAAACAGTTTCCTAATATACAGTATTTGAAAGTGCTTGCCATATTGGCTCT
CTCATTTTCATCTTCACCATCAACAGAGAGAGCAGCATACTTGCTTGCAGAACTGAACTTAGA
TCCAACCGCAGCTTGGCATCTTCGGTGGCCTGCAGCTCGTCCTCCAGCTCTTCCAGCTGCGTC
CGGCCTCCCAAAGTGCTGGGATTACAGGCATGAGCCACCGCGCTCTGCGAGGTACTTTTTCTA
于是我想,这还不简单,直接wc -c
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | wc -c
1600000
但是,这居然和答案不对!居然多统计了25000.。。。等等,25000不就是第一题统计多少读长的答案吗
$ zcat SRR1039510_1.fastq.gz | grep '@SRR'| wc -l
25000
插播一点题外话,昨天“小二黑”直接统计行数
$ zcat SRR1039510_1.fastq.gz | wc -l
100000
老师说,再计算一下就好:每4行一个read,除以4就好了。于是我联想起之前“萌哥”讲过bc这个命令,还自己搞了一个“花样”出来:
$ echo $(zcat SRR1039510_1.fastq.gz | wc -l)
100000
$ echo $(zcat SRR1039510_1.fastq.gz | wc -l)/4
100000/4
$ echo $(zcat SRR1039510_1.fastq.gz | wc -l)/4 | bc
25000
这姑且不说。
多统计出来25000个碱基,看起来似乎是每一行多统计了一个字符,那么多出来的这个字符是什么呢?联想一下之前在某处似乎听过,每行末尾的换行符是会计算进去的。于是我cat -A了一下。
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | cat -A | head
TGGGAGGCTGAGGCAGGAGAATCACTTAAACCTGGGAGGCAGAGGTTACAGTGAGCCGAGATT$
AAAGAAGGCGACAGTGAGAAGGAGTCCGAGAAGAGTGATGGAGACCCAATAGTCGATCCTGAG$
CTGCTGGGCCCCAAGGTCCTCCTGGTCCCAGTGGTGAAGAAGGAAAGAGAGGCCCTAATGGGG$
CTTGGCTGCAGCCATCCCGCTTAGCCTGCCTCACCCACACCCGTGTGGTACCTTCAGCCCTGG$
TGAGACAGGTAATTCAGTATAGTAGATTAATATTTTTAATATATATTTTCCCTTAAGATTTCC$
ATTTCTCAGTGTAGAAATCATGTCTTCTTAATTGCTGAACCTTACTGCAAAAACTTGTGATGT$
ATCAAGAATACCAAAACAGTTTCCTAATATACAGTATTTGAAAGTGCTTGCCATATTGGCTCT$
CTCATTTTCATCTTCACCATCAACAGAGAGAGCAGCATACTTGCTTGCAGAACTGAACTTAGA$
TCCAACCGCAGCTTGGCATCTTCGGTGGCCTGCAGCTCGTCCTCCAGCTCTTCCAGCTGCGTC$
CGGCCTCCCAAAGTGCTGGGATTACAGGCATGAGCCACCGCGCTCTGCGAGGTACTTTTTCTA$
然后突然想起
$ zcat SRR1039510_1.fastq.gz |head
@SRR1039510.1 HWI-ST177:290:C0TECACXX:1:1101:1373:2104 length=63
TGGGAGGCTGAGGCAGGAGAATCACTTAAACCTGGGAGGCAGAGGTTACAGTGAGCCGAGATT
+SRR1039510.1 HWI-ST177:290:C0TECACXX:1:1101:1373:2104 length=63
HJJJIJJJJJJJJIJJJGHHIJIIIIIIJJEHGGIJGIJIJJIJHHHGGFFDFFFDEDDDBDC
@SRR1039510.2 HWI-ST177:290:C0TECACXX:1:1101:1340:2124 length=63
AAAGAAGGCGACAGTGAGAAGGAGTCCGAGAAGAGTGATGGAGACCCAATAGTCGATCCTGAG
+SRR1039510.2 HWI-ST177:290:C0TECACXX:1:1101:1340:2124 length=63
HJJJJJJJJJJJIJIIGIJJJJGJHJJJHHDFFFE@CEEEDDDDDDDDDDDDDDDBDDDDDDD
@SRR1039510.3 HWI-ST177:290:C0TECACXX:1:1101:1273:2183 length=63
CTGCTGGGCCCCAAGGTCCTCCTGGTCCCAGTGGTGAAGAAGGAAAGAGAGGCCCTAATGGGG
人家这里都告诉你每个read的长度是63,于是计算一下
$ echo 63*25000 |bc
1575000
果然就是正确答案。
说明:1,的确每行多统计了一个字符;2,且多统计的是行末的换行符。
然后我想怎么把准确的数字统计出来,那就需要把行末的换行符去掉。于是:
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | sed 's/\n//g' | wc -c
1600000
发现并没有删除掉换行符。于是陷入了各种尝试,验证,怀疑……
最后在网上搜到了一个答案:
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | sed -e ':a;N;s/\n//g;ta' | wc -c
1575001
这个。。。似乎是去掉换行符了,但是。。怎么还多一个。。。
于是又开始猜想,可能是最后一个换行符没有删掉,为什么没有删掉呢,可能这个命令不适合我,需要再调整。于是又学习了这里面的冒号:t a N都是些什么意思,怎么用的。。。。
然后发现,确实没有错,就是最后一个换行符没有删掉。
zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | sed -e ':a;N;s/\n//g;ta' | cat -A
刷屏中……GATGGGGATCTGGCTCATGTCCAAAGGTGCAATATCAAGGAAGGGCAGGCGTGATGGCTTATTTGTTTTGTATTCAATGAATTTACACAGTCTCAGATTATCTCCTAACTCCCCACAAGACACTTATTTATTCCAAAGAAAGAACCAAAACTCCTGATGATGAAGGCCAGGGCCTCACGGGGCACCTCTCGGTTCAGGAAGAACTTCCATCGCTCGGCTGTTGGACCGGAACCAGGATGCAACTGAGGACACTGACGTGCAGAACATGAGGTGGCTTCTTGCAGTTCTCCCTGTAGACCCACGATACCAGCTGTCGGTTTTGTCAATGAAGTCCAGGCTCAGGCCCCCGGGCCCGATCATGGCCCCAGTCCGCACAGAGCGCCCGGCCCTGGCCGGTGTGGACAGAACTGGGGGCAAAAACAAAAAAGAAGGAAGGAAGGAAAGAAAGAAATGGGTAT$
N在这里把所有的序列合成1行了,然后再输出的,最后带一个换行符。
到这里彻底放弃sed了,脑雾之后想起tr还可以用,于是又尝试一下。
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | tr -d '\n' | wc -c
1575000
终于得到了正确答案!
但是为什么sed替换掉换行符,最后一个还留着呢?为什么不用标签来写script就一个也替换不掉呢?
因为(参考:http://yysfire.github.io/linux/sed-usage-summary.html 或者https://blog.csdn.net/u011729865/article/details/71773840)
sed 维护着两个数据缓存区:模式空间和保留空间。两者均被初始化为空。
sed 对输入的每一行运行一次如下所述的执行周期:首先,sed 从输入流中读入一行,并删除行末的换行符,将此行的内容放入模式空间。然后,脚本里的命令被执行;可以对每一个命令指定地址(地址相当于一种条件,只有条件被满足,才会执行紧跟其后的命令。当到达脚本的结尾,模式空间的内容(如果之前行末的换行符被删除,此时会被加回来)被写入到输出流(除非使用了选项'-n')。然后,对下一行开始下一个执行周期。
标签的使用参考上述地址或者:http://blog.chinaunix.net/uid-20943515-id-403.html
man一下sed,发现有个-z选项,可以用空字符作为每行的分割
-z, --null-data
separate lines by NUL characters
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | sed -z 's/\n//g'| wc -c
1575000
其实不纠结于sed,可以用awk来实现:
$ zcat SRR1039510_1.fastq.gz | sed -n '2~4p' | awk '{print $0}' ORS='' | wc -c
1575000