shell字符串单双引号的坑
入门生信时,我最接触的编程语言是python和R,最后才是shell。学习shell时,我也只是草草了事,没有仔细对比三种编程语言间的差别和特点,自认为很聪明的把python和R的相关基础知识直接迁移到了shell。最近踩到了坑,才让我意识到:基础不牢,缺乏思考,非常吃亏!
问题描述:
批量进行bwa比对,代码如下:
for i in {1..9}
do
bwa mem -t 2 -R '@RG\tID:W0${i}\tSM:W0${i}\tPL:illumina' \$ref ./$W0{i}_1.fq.gz ./$W0{i}_2.fq.gz | samtools sort -@ 2 -m 1G -o ./W0${i}.sort.bam -
done
运行非常成功!结果正常输出!然后我就愉快地去重并call variant,但是当我查看g.vcf文件时发现样本名为W0这是怎么回事?为了确定这几个文件的样本名是不是都为{i},我运行了一下命令
for i in `ls *.g.vcf`
do
grep -n -G 'W0${i}' ${i}
done
输出结果如下:
得,全是这么诡异符号。我又查看了每个bam文件的RG行没错,所有bam文件RG行的ID、SM都是W0${i}!!!
解决问题:
通过以上的探索,已经能确定是比对那一步'@RG\tID:W0${i}\tSM:W0${i}\tPL:illumina'
该字符串中的变量没有被解释。
这就奇怪了,代码看着很正常呀,那么用echo命令测试一下:
变量确实没有被解释!原因在哪呢?把单引号换成双引号试试:
噢!原来是引号的问题
寻找原因
为什么会这样子呢?在shell中单引号和双引号括起来的字符串有什么不同吗?
(截图来自 C语言中文网)
很明显,我犯的错误属于第一种情况:由单引号包围的字符串任何字符都会原样输出,在其中使用变量是无效的!。根据截图所言,推而广之:我们在命令行中使用的各种命令、运行的各种软件本质上都是字符串,只不过我们没有加上 单引号或双引号作为标识,属于 第三种情况。
这种规则让我们能够通过空格来区分命令中的选项和参数。同理,命令加上双引号或单引号它也应该能够正常运行:
所以为了以后的万无一失,写shell脚本有变量替换的情况就用 ${变量名} 的格式。养成一个好的习惯是非常重要的....由于小小的字符串问题,我现在就需要把已经生成的bam文件的标签和g.vcf文件中的样本名都替换掉...如果不及时替换可以想象到在最后genotypegvcf时,我最后的得到的结果里会莫名其妙的少好几个样本变异信息。
所以Linux的shell命令学好 是非常有必要哦:
大家一定要把Linux的6个阶段跨越过去 ,一般来说,每个阶段都需要至少一天以上的学习:
第1阶段:把linux系统玩得跟Windows或者MacOS那样的桌面操作系统一样顺畅,主要目的就是去可视化,熟悉黑白命令行界面,可以仅仅以键盘交互模式完成常规文件夹及文件管理工作。 第2阶段:做到文本文件的表格化处理,类似于以键盘交互模式完成Excel表格的排序、计数、筛选、去冗余,查找,切割,替换,合并,补齐,熟练掌握awk,sed,grep这文本处理的三驾马车。 第3阶段:元字符,通配符及shell中的各种扩展,从此linux操作不再神秘! 第4阶段:高级目录管理:软硬链接,绝对路径和相对路径,环境变量。 第5阶段:任务提交及批处理,脚本编写解放你的双手。 第6阶段:软件安装及conda管理,让linux系统实用性放飞自我。
写在文末
其实正常情况下初学者写的脚本应该是先echo看一眼,然后再运行,echo这个命令太重要了!