3. Snakefile 基本结构:规则、输入输出、Shell 指令
Snakefile 说白了就是工作流的“剧本”。
我刚接触 Snakemake 时,以为它就是 Makefile 的 Python 亲戚,结果发现远比那灵活。今天我把最核心的三个部分——规则定义、输入输出、Shell 指令——拆开揉碎了讲清楚。
3.1 规则:工作流的最小单元
每个规则就像生产线上的一个工位。我习惯把规则想象成“一个文件到另一个文件的转换过程”。
基本结构长这样:
rule 规则名称:
input:
"输入文件路径"
output:
"输出文件路径"
shell:
"执行的命令"
为什么要有规则名?
- 方便调试时定位
- 可以被其他规则显式调用
- 日志输出时能看到是哪个规则在执行
命名建议:用下划线分隔的动词+名词组合,比如
trim_fastq、align_bam。别用中文或特殊字符。
3.2 输入输出:定义依赖关系
Snakemake 最聪明的地方在于——它通过输入输出自动识别依赖关系。
你想想看,如果规则 A 的输出是规则 B 的输入,那 A 必须在 B 之前运行。Snakemake 会自动排序。
举个例子:
rule download_data:
output:
"raw_data/sample1.fastq.gz"
shell:
"wget -O {output} https://example.com/sample1.fastq.gz"
rule trim_reads:
input:
"raw_data/sample1.fastq.gz"
output:
"trimmed/sample1_trimmed.fastq.gz"
shell:
"fastp -i {input} -o {output}"
trim_reads 需要 download_data 的输出,Snakemake 就知道先下载,再裁剪。
路径陷阱:我曾经因为路径写错,浪费了一整天。
input 和 output 里尽量用绝对路径,或者确保工作目录正确。
3.3 Shell 指令:真正干活的命令
Shell 指令就是规则要执行的真正命令。
你可以写 bash 命令、Python 脚本、甚至是 R 代码——只要能在终端运行。
关键语法:
{input}:自动替换成 input 里的文件路径{output}:自动替换成 output 里的文件路径- 多个输入输出时用索引:
{input[0]}、{output[1]}
看这个实际案例:
rule fastqc_trimmed:
input:
"trimmed/sample1_trimmed.fastq.gz"
output:
"qc/trimmed/sample1_fastqc.html",
"qc/trimmed/sample1_fastqc.zip"
shell:
"""
fastqc {input} -o qc/trimmed/
"""
多命令技巧:Shell 里可以写多行命令,用
&& 连接,或者用 Python 的 run: 指令代替。
3.4 实战案例:一个完整的质控流程
把上面三个部分组合起来,就是一个完整的 Snakemake 工作流。
下面是我在项目中用过的质控流程骨架:
rule get_fastq:
output:
"data/sample.fastq.gz"
shell:
"""
wget -O {output} ftp://example.com/sample.fastq.gz
"""
rule raw_qc:
input:
"data/sample.fastq.gz"
output:
"qc/raw/sample_fastqc.html"
shell:
"""
fastqc {input} -o qc/raw/
"""
rule detect_adapters:
input:
"data/sample.fastq.gz"
output:
"reports/adapters.txt"
shell:
"""
cutadapt --detect-adapter-for-pe -o /dev/null {input} 2> {output}
"""
rule trim:
input:
fastq="data/sample.fastq.gz",
adapter="reports/adapters.txt"
output:
"trimmed/sample.fastq.gz"
shell:
"""
cutadapt -a file:{input.adapter} -o {output} {input.fastq}
"""
rule trimmed_qc:
input:
"trimmed/sample.fastq.gz"
output:
"qc/trimmed/sample_fastqc.html"
shell:
"""
fastqc {input} -o qc/trimmed/
"""
这个流程的依赖关系很清楚:
- 先下载原始数据
- 对原始数据做 FastQC
- 检测接头序列
- 根据检测结果做裁剪
- 对裁剪后的数据再做一次质控
用
input: 命名参数:上面 trim 规则里,我用了 input.fastq 和 input.adapter,这样在 shell 里引用时更清楚。这是我在实践中养成的习惯。
3.5 知识结构图
下面这张图把 Snakefile 的核心结构画了出来,方便你对照记忆:
3.6 避坑指南
说几个我踩过的坑:
- 输入输出不匹配:output 写了两个文件,但 shell 只生成一个,Snakemake 会报错。
- 路径歧义:同一个文件名出现在不同目录,Snakemake 会傻眼。要用
wildcard区分。 - 命令太长:Shell 指令超过两行时,记得用
"""包裹,不然容易断句出错。
我曾经因为忘记在 shell 命令里加
{output},结果文件死活生成不了。Snakemake 检查的是 output 字段里的文件是否存在,不是看你命令里生成了什么。
3.7 表格总结:不同场景下的规则写法
| 场景 | 输入 | 输出 | Shell 示例 |
|---|---|---|---|
| 单文件 | 单个文件 | 单个文件 | fastq {input} -o {output} |
| 多输入 | 多个文件 | 单个文件 | cat {input[0]} {input[1]} > {output} |
| 多输出 | 单个文件 | 多个文件 | split -l 1000 {input} {output[0]} |
| 无输入 | 无 | 单个文件 | echo "hello" > {output} |
| 无输出 | 单个文件 | 无 | rm {input} |