第三章:第一个Snakemake流程:编写简单的Snakefile,运行流程

说实话,很多教程上来就甩一堆规则、通配符、配置,看得人头皮发麻。我个人习惯是先跑起来一个最小例子,亲眼看到输出文件生成,心里再踏实。这一章我们就干一件事——写一个最简单的Snakefile,然后敲命令让它跑通。

3.1 准备工作:文件和目录结构

先搭个基础环境。你随便找个空目录,比如my_first_flow,在里面放一个输入文件input.txt,内容就写几行文本:

hello world
snakemake is fun
let us start

然后在这个目录里再新建一个空文件,命名为Snakefile——注意首字母大写,没有后缀。Snakemake默认就找这个名字的文件。

小习惯: 我每建一个新项目都会先写好Snakefile和README.md,哪怕规则为空,因为后面加东西时大脑负担小。

3.2 编写你的第一个Snakefile

在Snakefile里写入下面内容。别复制粘贴,最好手打一遍,感受一下语法:

rule sort_lines:
    input:
        "input.txt"
    output:
        "output.txt"
    shell:
        "sort {input} > {output}"

我们来拆解一下这个规则(rule):

  • sort_lines是这个规则的名字,随你起,但最好有意义。我在项目中见过有人直接写rule one,维护时根本不知道它在干啥。
  • input:指定输入文件,这里就是input.txt。
  • output:指定输出文件,Snakemake会用这个文件名来追踪是否已生成。
  • shell:告诉Snakemake执行哪条shell命令。注意花括号{input}和{output}会被自动替换成实际文件名。
关键一件事: output是触发流程的钥匙。Snakemake只会生成你在命令行里要求的目标文件,然后反向推导需要执行哪些规则。

3.3 运行流程

现在打开终端,进入你的项目目录,执行:

snakemake -c1 output.txt

-c1表示使用1个CPU核心。第一次运行你会看到类似这样的输出:

Building DAG of jobs...
Using shell: /bin/bash
Provided cores: 1
Rules claiming more threads will be scaled down.
Job stats:
job         count    min threads    max threads
--------    -----    -----------    -----------
sort_lines       1              1              1

[Wed Jan 24 10:15:22 2024]
rule sort_lines:
    input: input.txt
    output: output.txt
    jobid: 0
    reason: Missing output files: output.txt
    resources: tmpdir=/tmp

sort input.txt > output.txt

运行结束后,看看目录:多了一个output.txt。打开它,发现内容已经被按字母排序了。嗯,就是这么简单。

曾经有个坑: 我记得第一次用Snakemake时直接把输出文件写成output.txt,然后第二次运行时报错“文件已存在”。Snakemake默认不允许覆盖已有输出。你要么删除文件重新跑,要么加--force参数。后来我就养成了每次实验前先snakemake --delete-all-output清干净的习惯。

3.4 理解Snakemake干了什么

你可能觉得这不就是一行sort命令吗?直接敲也能做。但你想想看,如果后面有上百个文件,每个都要先排序再压缩再比对……手工逐个执行会疯掉的。Snakemake的价值在于它帮你自动构建依赖图。

下面这张图展示了一个完整的工作流周期——从你编写Snakefile到获得最终输出,Snakemake帮你省掉了大量体力活:

一个Snakemake流程的完整周期 编写 Snakefile 定义规则 (rule) 指定 input / output 编写 shell snakemake 目标文件 构建 DAG 图 执行并生成文件 虚线表示 Snakemake 自动完成

你看,Snakemake替你完成了最繁琐的两步:① 当多个规则串联时,自动解析依赖关系,决定谁先执行;② 检查输出文件是否已经存在,避免重复劳动。

3.5 核心语法速查

下面这个表格是我在带团队时经常贴在白板上的,初学阶段记住这四个关键字就够了:

关键字 作用 是否必须
rule 定义一个规则,后面跟规则名(如 sort_lines) 是
input 指定该规则需要的输入文件(可多个) 否,但一般会用
output 指定该规则产生的输出文件 是(除非用 nooutput)
shell 写入要在 shell 中执行的命令,用 { } 引用 input/output 是(或改用 run)
一个实用技巧: 如果你不确定某个规则会不会跑,先用 snakemake --dryrun 目标文件。它只会打印出计划执行的命令而不真正运行,非常安全。
我在大项目里几乎每次提交代码前都会先 dryrun 一遍,确认逻辑没断。

3.6 避坑指南:你很可能遇到的三个问题

  • 输出现成文件被杀:再次运行相同的 snakemake output.txt 会提示“Nothing to be done”。想重新跑?加 -f 或 --force,或者删掉输出文件。
  • 命令写错没提示:Snakemake 本身不校验 shell 命令是否正确,它只管执行。如果输出了错误日志,它也不会自动终止(除非设置 wms_monitor)。我习惯在 shell 命令最后加 && echo "done" 来辅助调试。
  • 路径问题:Snakemake 默认以当前工作目录执行 shell 命令。如果输入文件在子目录,一定要写相对路径,比如 "data/input.txt",否则会报 FileNotFoundError。