第四章:第一个工作流——编写简单规则、运行、查看输出

咱们正式动手了。前面聊了那么多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里写的文件名。我个人习惯用占位符,而不是硬编码文件名,这样改起来方便得多。

关键点:Snakemake会自动创建输出文件所在的目录(包括多级子目录),不需要你手动mkdir。不过如果输出路径拼错了……嗯,它会老老实实创建一个空目录,然后卡住。

运行你的第一条规则

把上面的代码保存为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不会创建任何文件,包括输出目录。如果你需要测试目录结构,可以用snakemake --summary,它会告诉你哪些文件已存在、哪些需要生成。

规则的本质——一句话总结

Snakemake的一条规则,说白了就是三要素:

  • 输入(input)——可选,有些规则不需要输入
  • 输出(output)——必须至少一个
  • 运行方式——用shell、run(Python代码块)、script(调用外部脚本)等

你不需要关心规则之间的执行顺序,Snakemake会从最终目标文件反推依赖关系。这是它比Make省心的地方。我刚开始用Make写生物信息流程时,经常因为依赖顺序搞错而重跑整个流程;换成Snakemake后就再没犯过这种错。

本章核心流程一览

下面这张图帮你梳理出一条规则从定义到执行的完整路径:

Snakemake 单规则工作流 编写 Snakefile 指定 input(可选) 声明 output shell / run / script snakemake 命令 检查生成的文件 文件不存在时 Snakemake 自动回溯依赖链,无需手动指定执行顺序

从编写规则到检查输出,一共六步,但绝大多数时间你只需要关注前两步——定义规则和声明输出。剩下的事情Snakemake帮你包办了。

常见问题与避坑

问题 现象 解决方法
Snakefile未找到 报错 "Snakefile not found" 确认文件名大小写,Snakemake 默认查找 Snakefile,也可以用 -s 指定
输出文件路径错误 生成的文件在奇怪的位置 使用相对路径,或者提前用 --dry-run 预览输出路径
shell 命令拼写错误 报错 "Non-zero exit code" 先用 -p 看实际执行的命令,复制到终端手动试
输入文件不存在 Snakemake 自动寻找生成它的规则 确保上游规则存在且输出路径匹配
我的习惯:每次编写新规则后,先用snakemake -n -p干跑一次,确认命令和文件路径都没问题再正式运行。这招帮我省了至少一半的调试时间。

小结

今天你亲手写出了第一条Snakemake规则,让它生成了一个文件。你也看到了输入输出如何串联成工作流,以及怎么用干跑模式提前发现错误。这些都是最基础但最核心的操作——后面的每一章都会基于这个框架展开。记住那句口诀:写规则、定输入输出、选运行方式、干跑预览、正式执行、检查结果。重复几遍就成习惯了。