第4章 命令行参数传递:--key=value 的正确姿势
如果你用过 Nextflow 的 CLI,肯定对 --input、--outdir 这些参数不陌生。说白了,这就是我们覆盖默认参数最直接的方式。我个人习惯在写 pipeline 时,把经常变的参数全部暴露出来,用 --key=value 让用户在命令行里一键覆盖。
但问题来了——参数值里带空格怎么办?路径里有特殊符号怎么处理?引号套引号会不会炸?今天我们就专门聊聊这些坑。
基础用法:最简单的覆盖
先看一个典型场景。假设你的 nextflow.config 里定义了一个默认参数:
params {
input = "/data/sample1.fastq"
outdir = "./results"
}
你在命令行里想用另一个文件,直接写:
nextflow run main.nf --input="/data/sample2.fastq"
这就覆盖了默认值。注意等号两边不要加空格,否则 shell 会把它拆成两个参数。我刚开始学 Nextflow 时踩过这个坑,写成了 --input = "/data/xxx",结果参数没传进去,debug 了半天。
对了,你也可以用空格分隔的格式:
nextflow run main.nf --input "/data/sample2.fastq"
两种写法在 Nextflow 里效果一样,但个人建议用等号——更清晰,一眼能看出键值对关系。
空格与路径:引号是救命稻草
假设你的样本文件放在 /my data/sample.fastq——注意路径里有空格。这时候如果你直接写:
nextflow run main.nf --input=/my data/sample.fastq
Shell 会把 --input=/my 当作一个参数,data/sample.fastq 当作另一个。Nextflow 会一脸懵逼。
解决方案?加引号:
nextflow run main.nf --input="/my data/sample.fastq"
或者用单引号:
nextflow run main.nf --input='/my data/sample.fastq'
单双引号有什么区别?
| 引号类型 | 变量展开 | 转义 | 推荐场景 |
|---|---|---|---|
双引号 " |
会展开 $var 和 `cmd` |
保留 \$ 等转义序列 |
需要嵌入 shell 变量时 |
单引号 ' |
不做任何展开 | 所有字符原样传递 | 路径含 $ 或反引号时 |
举个例子,你的路径里刚好有 $HOME 这个字符串(不是环境变量),用单引号:
nextflow run main.nf --input='/data/$HOME/sample.fastq'
这样传进去的值就是 /data/$HOME/sample.fastq 的字面量。如果用双引号,shell 会把它展开成 /data/your_home_dir/sample.fastq,可能就不是你想要的了。
'),那就得用双引号包裹,或者用反斜线转义。我个人建议别在路径里放单引号,设计 pipeline 时就避开这些古怪字符。
引号里的引号:嵌套的正确打开方式
有时候参数值里既有空格又有引号,比如你要传给工具一个字符串 sample "A"。直接写会出问题:
nextflow run main.nf --param='sample "A"' # 外层单引号,内层双引号可以
这没问题,因为单引号里的双引号只是普通字符。反过来也行:
nextflow run main.nf --param="sample 'A'"
但千万别外层双引号、内层双引号不加转义:
nextflow run main.nf --param="sample "A"" # ❌ shell 会解析错误
这时候要加反斜线:
nextflow run main.nf --param="sample \"A\""
嗯,写起来有点丑。我通常直接改用单引号包外层,省心。
log.info "params.myparam: ${params.myparam}",先看看实际接收到的值——我在调试参数传递时经常这么干。
复杂参数:JSON 和列表
Nextflow 支持参数值是 JSON 字符串,比如:
nextflow run main.nf --config='{"threads": 4, "memory": "8G"}'
注意这里用了单引号包住整个 JSON,因为 JSON 里含双引号。如果你用双引号包,内部的双引号就得转义,可读性很差。
对于列表参数,你可以多次传递同一个 key:
nextflow run main.nf --sample=s1.fastq --sample=s2.fastq
Nextflow 会把 params.sample 变成一个列表 ["s1.fastq", "s2.fastq"]。如果列表里也有空格,每个值单独加引号:
nextflow run main.nf --sample="/my data/s1.fastq" --sample="/my data/s2.fastq"
避坑指南:我曾经遇到的几个真实案例
有一次我在生产环境传了一个路径:--indir=/data/raw/ (v1.0)——注意路径末尾有括号。结果 shell 把括号当成子 shell 表达式,直接报语法错误。解决方案:要么用引号包起来,要么把括号去掉。我现在写路径都强制不加特殊符号,只保留字母、数字、下划线、横线、点、斜线。
另一个坑是参数值以 -- 开头。比如你想传 --flag 作为值:
nextflow run main.nf --option=--flag # Nextflow 可能把它当成新参数
这种情况下要加等号并保证整个值被引号包裹,或者用 --option=--flag 这样写。我建议如果值以横线开头,直接用引号括死。
参数传递流程(SVG)
最佳实践总结
- 路径有空格 → 必须加引号。单双皆可,注意内部引号冲突。
- 参数值包含
$、\、`→ 用单引号,禁止 shell 展开。 - 参数值包含
'→ 用双引号,内部单引号无需转义。 - 参数值本身就是引号字符 → 用反斜线转义,或者换一种参数组织形式。
- 重复传递同一 key → 自动合成列表,适用于样本列表等场景。
- 测试时打印日志,确认实际传入值是否符合预期。
我个人习惯在项目根目录放一个 run.sh 脚本,把常用参数写进去,用变量代替直接写死。这样既保留灵活性,又避免每次敲长长一串:
#!/bin/bash
INPUT="/path/to/input data.fastq"
OUTDIR="./results/$(date +%Y%m%d)"
nextflow run main.nf --input="$INPUT" --outdir="$OUTDIR"
双引号展开 $INPUT 和 $OUTDIR,又能保留空格,一举两得。
好了,关于命令行参数传递的核心技巧就聊到这。你想想看,是不是很多坑都是引号引起的?掌握了这些,下次遇到 --input=my file.txt 报错,你就知道怎么修了。