3. Snakefile 语法入门归纳总结
Snakefile 是整个流程的大脑。
说白了,它就是一套用 Python 语法写的工作说明书。
你把每一步该做什么、用什么文件、产生什么结果写进去,Snakemake 就自动帮你按顺序执行,还能并行跑。
3.1 Snakefile 长得像什么
我第一次见到 Snakefile 时,还以为是 Makefile 的变种。
其实它就是个带扩展语法的 Python 文件。
每条核心指令叫 rule,一个规则定义一个处理步骤。
来看最简版本:
rule fastqc:
input:
"sample1.fastq"
output:
"sample1_fastqc.html",
"sample1_fastqc.zip"
shell:
"fastqc sample1.fastq"
嗯,结构很清晰:输入、输出、要执行的命令。
3.2 规则的骨架:输入、输出、动作
每个 rule 至少需要这三样东西。我个人习惯先写输出,因为 Snakemake 靠输出来判断任务是否完成。
| 组件 | 作用 | 必须吗 |
|---|---|---|
| input | 上游文件列表 | 否(没有输入就是第一条规则) |
| output | 本规则产生的文件 | 强烈建议 |
| shell / run | 执行命令或 Python 代码 | 是(至少选一个) |
小技巧:输出文件最好带明确的样本名或批次号,方便后期排查。
3.3 动作的两种写法:shell vs run
shell 后面跟字符串命令,适合调用外部工具。
run 后面跟 Python 代码块,适合做逻辑处理或调用 Python 库。
rule count_lines:
input:
"sample.fastq"
output:
"counts.txt"
run:
import subprocess
result = subprocess.run(["wc", "-l", input[0]], capture_output=True, text=True)
with open(output[0], "w") as f:
f.write(result.stdout)
我个人更推荐 shell——除非你需要复杂的条件判断,否则 shell 更简洁、更容易 debug。
3.4 通配符:让一条规则适配所有样本
如果每个样本写一条规则,你会疯掉的。
所以 Snakemake 用通配符 {样本名} 这种占位符,让一条规则处理所有文件。
rule fastqc_wildcard:
input:
"{sample}.fastq"
output:
"{sample}_fastqc.html",
"{sample}_fastqc.zip"
shell:
"fastqc {input}"
当你让 Snakemake 生成 sampleA_fastqc.html 时,它会自动把 {sample} 替换成 sampleA。
我记得第一次用通配符时,一直纠结要不要写多字符模式,其实 {sample} 就能匹配任意文件名(不包含斜杠)。
3.5 规则依赖:Snakemake 如何决定顺序
Snakemake 不关心你写规则的先后顺序。
它只看 输出文件 是不是别的规则的 输入文件。
如果规则 B 的输入等于规则 A 的输出,Snakemake 就知道先跑 A 再跑 B。
例如:
rule trim:
input:
"{sample}.fastq"
output:
"{sample}_trimmed.fastq"
shell:
"cutadapt -o {output} {input}"
rule fastqc_trimmed:
input:
"{sample}_trimmed.fastq"
output:
"{sample}_trimmed_fastqc.html",
"{sample}_trimmed_fastqc.zip"
shell:
"fastqc {input}"
当你请求 sampleA_trimmed_fastqc.html 时,Snakemake 自动推导出依赖链:先 trim 生成 trimmed.fastq,再 fastqc 生成 html。
3.6 用 all 规则定义最终目标
实际项目中,你不会一个个手动指定要哪些文件。
习惯上会在 Snakefile 开头写一条 rule all,把最终需要的文件列在 input 里。
rule all:
input:
expand("{sample}_trimmed_fastqc.html", sample=["A","B","C"])
这样只要运行 snakemake,它会自动生成所有样本的质控报告。
3.7 全局配置与函数
你可以在 Snakefile 顶部定义 Python 变量、函数,甚至读取配置文件。
import pandas as pd
SAMPLES = pd.read_csv("samples.csv")["sample_id"].tolist()
rule all:
input:
expand("{sample}_fastqc.html", sample=SAMPLES)
关键点:Snakefile 本质是 Python,所以能用 os.path.join、glob、字典 等任何 Python 特性。
3.8 避坑指南:我踩过的三个坑
- 路径问题:我曾经在 shell 命令里写相对路径
fastqc {input},结果 Snakemake 的工作目录不是你想象的目录。后来我改用{input}的绝对路径,或者用workdir:指令固定目录。 - 通配符冲突:如果两个规则使用同样的通配符名字但不同格式,Snakemake 会报错。比如
{sample}.txt和{sample}.bam没问题,但{sample}_a和{sample}_b可能出歧义。 - 漏写 output:有一次我忘了把日志文件写到 output 里,结果 Snakemake 觉得任务没完成,每次都要重跑。
警告:通配符不能与 Python 的关键字重名(比如 input、output)。
3.9 本章知识体系 SVG
这张图帮你理清层次:Snakefile 包含多条规则,每条规则有输入、输出、参数、执行方式,规则通过通配符和依赖推断自动形成 DAG,最后 Snakemake 按照 DAG 并行执行。
3.10 趁热练手:一个完整的小例子
假设你有三个 fastq 文件,要做质控:
# Snakefile
SAMPLES = ["sample1", "sample2", "sample3"]
rule all:
input:
expand("{s}_fastqc.html", s=SAMPLES)
rule fastqc:
input:
"{sample}.fastq"
output:
"{sample}_fastqc.html",
"{sample}_fastqc.zip"
shell:
"fastqc -o . {input}"
运行 snakemake -j 3,三个样本同时跑。
是不是比写三个脚本清爽多了?
试一下:把 -j 3 改成 -j 1,看看顺序执行的日志。
3.11 小结
Snakefile 的核心就这些:
- 规则(rule)是基本单元
- 通配符让规则一次定义多次使用
- 依赖自动推导,不用手动控制顺序
- 可以混用 Python 增强灵活性
把这些记牢,后面学高级功能就轻松了。我当年就是靠这三个概念啃完整个项目的。