如何使用Bash按条件过滤FASTQ格式文件中的行?
嘿,我来帮你搞定FASTQ文件的Bash过滤问题~
首先得记住:FASTQ是四行一组存储测序reads的格式,每组对应一个read——第1行是@开头的标识符,第2行是测序序列,第3行是+开头的分隔行,第4行是对应序列的质量值。过滤时一定要完整保留符合条件的整个read,不能只挑单行处理,不然文件结构就乱了。
下面是几种常见过滤场景的具体实现,用Bash里最常用的awk工具(效率高,处理大文件也没问题):
1. 保留序列长度达标的reads
比如想留下序列长度≥50的reads:
awk 'BEGIN{OFS="\n"} {r[NR%4]=$0} NR%4==0 {if(length(r[2])>=50) print r[1],r[2],r[3],r[4]}' input.fastq > filtered.fastq
逻辑很简单:用数组r缓存每组的4行,当处理完一组(NR%4==0)时,检查第2行(序列行)的长度,符合要求就输出整个read的4行。
2. 去掉序列里含N的reads
如果你的数据里有不确定的碱基(N),想过滤掉这些reads:
awk 'BEGIN{OFS="\n"} {r[NR%4]=$0} NR%4==0 {if(r[2] !~ /N/) print r[1],r[2],r[3],r[4]}' input.fastq > filtered.fastq
这里用正则匹配r[2](序列行),如果不含N就输出整组。
3. 根据质量值过滤(比如平均质量≥20)
假设你的质量值是最常用的Phred+33编码(ASCII码减33得到实际质量值),计算平均质量后过滤:
awk ' BEGIN{OFS="\n"} { r[NR%4] = $0 } NR%4 == 0 { sum = 0 len = length(r[4]) for(i=1; i<=len; i++) { sum += ord(substr(r[4], i, 1)) - 33 } avg = sum / len if(avg >= 20) print r[1], r[2], r[3], r[4] } function ord(c) { return sprintf("%d", c) } ' input.fastq > filtered.fastq
这段脚本会遍历质量行的每个字符,转成实际质量值后算平均值,达标就输出整个read。
4. 按标识符过滤(比如保留特定ID的reads)
如果想根据第1行的标识符筛选,比如保留ID里包含199563512的reads:
awk 'BEGIN{OFS="\n"} {r[NR%4]=$0} NR%4==0 {if(r[1] ~ /199563512/) print r[1],r[2],r[3],r[4]}' input.fastq > filtered.fastq
用正则匹配标识符行(r[1])里的目标字符串就行。
小提示
- 要是需要组合多个条件,比如同时保留长度≥50且不含N的reads,直接把条件用
&&连起来:
awk 'BEGIN{OFS="\n"} {r[NR%4]=$0} NR%4==0 {if(length(r[2])>=50 && r[2]!~/N/) print r[1],r[2],r[3],r[4]}' input.fastq > filtered.fastq
- 确保你的FASTQ是严格四行一组的,没有缺失或多余的行,不然脚本可能出问题
- 大文件优先用
awk,比纯Bash循环或者sed高效得多
内容的提问来源于stack exchange,提问作者Maria
相关产品推荐
相关产品推荐

