第四章:第一个工作流——编写简单规则、运行、查看输出
咱们正式动手了。前面聊了那么多Snakemake的理念,今天就把第一条规则写出来、跑起来、看看结果。你可能会想:“不就是写个规则嘛,能有多复杂?”嗯,我最初也是这么想的,结果第一次跑的时候连个输出目录都没建好,尴尬得很。
认识Snakefile——你的工作流脚本
Snakemake的核心是Snakefile,一个以纯文本保存的规则文件。它用Python语法(加了一些专属关键字)来描述“输入→处理→输出”的步骤。每个步骤叫一条rule。
一个最简单的Snakefile长什么样?
rule say_hello:
output: "hello.txt"
shell:
"echo 'Hello, Snakemake!' > {output}"
这条规则说:我想要生成一个叫hello.txt的文件;生成它只需要在shell里执行一句echo命令。注意{output}——这是Snakemake的占位符,它会自动替换成output里写的文件名。我个人习惯用占位符,而不是硬编码文件名,这样改起来方便得多。
运行你的第一条规则
把上面的代码保存为Snakefile(注意大小写),然后在终端里执行:
snakemake
Snakemake会自动寻找当前目录下的Snakefile,并且试图生成这条规则里定义的hello.txt。默认情况下,它会先打印出要执行的命令,再实际运行。输出类似:
Building DAG of jobs...
Job stats:
job count min threads max threads
say_hello 1 1 1
[Mon Mar 11 11:22:00 2025]
rule say_hello:
output: hello.txt
jobid: 0
Finished job 0.
1 of 1 steps (100%) done
看到“Finished job 0”就说明跑完了。去目录看看,是不是多了一个hello.txt?
查看输出——别光看屏幕
Snakemake只管生成文件,不会帮你打开它。用cat或者文本编辑器看:
cat hello.txt
你应该看到“Hello, Snakemake!”。如果文件内容对不上,那就是shell命令写错了。我在项目中遇到过有人把单引号写成了反引号,结果shell报错,Snakemake也报错,排查了半天才找到原因。
输入与输出:让规则串联起来
单条规则太孤单了,工作流需要多个步骤接力。比方说:先用一个规则生成原始数据,再用另一个规则汇总。这就要用到input字段。
rule generate_data:
output: "raw.txt"
shell:
"seq 1 100 > {output}"
rule compute_sum:
input: "raw.txt"
output: "sum.txt"
shell:
"awk '{s+=$1} END {print s}' {input} > {output}"
现在执行snakemake,Snakemake会先检查compute_sum的输入文件是否存在,如果不存在就去执行generate_data。它自动构建了依赖关系图——也就是前面提过的DAG。你只管定义规则,顺序由Snakemake决定。
干跑模式——先别真动手
有时候你只是想看看Snakemake打算怎么执行,不想真的创建文件。Snakemake提供了-n(dry-run)和-p(print命令)选项:
snakemake -n -p
输出会列出每条规则要执行的shell命令,但不会真正运行。这是我最常用的调试手段。写了一个新规则时,我会先snakemake -n -p检查占位符替换是否正确,路径是否合理。有一次我写错了输出文件名,干跑模式一眼就看出来了,省了真跑才发现的尴尬。
snakemake --summary,它会告诉你哪些文件已存在、哪些需要生成。
规则的本质——一句话总结
Snakemake的一条规则,说白了就是三要素:
- 输入(input)——可选,有些规则不需要输入
- 输出(output)——必须至少一个
- 运行方式——用
shell、run(Python代码块)、script(调用外部脚本)等
你不需要关心规则之间的执行顺序,Snakemake会从最终目标文件反推依赖关系。这是它比Make省心的地方。我刚开始用Make写生物信息流程时,经常因为依赖顺序搞错而重跑整个流程;换成Snakemake后就再没犯过这种错。
本章核心流程一览
下面这张图帮你梳理出一条规则从定义到执行的完整路径:
从编写规则到检查输出,一共六步,但绝大多数时间你只需要关注前两步——定义规则和声明输出。剩下的事情Snakemake帮你包办了。
常见问题与避坑
| 问题 | 现象 | 解决方法 |
|---|---|---|
| Snakefile未找到 | 报错 "Snakefile not found" | 确认文件名大小写,Snakemake 默认查找 Snakefile,也可以用 -s 指定 |
| 输出文件路径错误 | 生成的文件在奇怪的位置 | 使用相对路径,或者提前用 --dry-run 预览输出路径 |
| shell 命令拼写错误 | 报错 "Non-zero exit code" | 先用 -p 看实际执行的命令,复制到终端手动试 |
| 输入文件不存在 | Snakemake 自动寻找生成它的规则 | 确保上游规则存在且输出路径匹配 |
snakemake -n -p干跑一次,确认命令和文件路径都没问题再正式运行。这招帮我省了至少一半的调试时间。
小结
今天你亲手写出了第一条Snakemake规则,让它生成了一个文件。你也看到了输入输出如何串联成工作流,以及怎么用干跑模式提前发现错误。这些都是最基础但最核心的操作——后面的每一章都会基于这个框架展开。记住那句口诀:写规则、定输入输出、选运行方式、干跑预览、正式执行、检查结果。重复几遍就成习惯了。