在Nextflow中,process是执行用户脚本的基本处理原语。
进程定义以关键字process
开始,接着是进程名,最后是用花括号分隔的进程体。进程主体必须包含一个表示命令的字符串,或者更一般地,包含由它执行的脚本。一个基本流程如下所示:
process sayHello {
"""
echo 'Hello world!' > file
"""
}
一个流程可以包含五个定义块,分别是: directives, inputs, outputs, when子句和process script。语法定义如下:
process < name > {
[ directives ]
input:
< process inputs >
output:
< process outputs >
when:
< condition >
[script|shell|exec]:
< user script to be executed >
}
脚本(script)
脚本块是一个字符串语句,它定义了进程执行任务时所执行的命令。
一个进程包含且仅包含一个脚本块,当进程包含输入和输出声明时,它必须是最后一条语句。
输入的字符串在主机系统中作为Bash脚本执行。它可以是您通常在终端shell或公共Bash脚本中使用的任何命令、脚本或它们的组合。脚本语句中可以使用的命令的唯一限制是目标执行系统中这些程序的可用性。
脚本块可以是一个简单的字符串或多行字符串。后者简化了由跨多行多个命令组成的非简单脚本的编写。例如:
process doMoreThings {
"""
blastp -db $db -query query.fa -outfmt 6 > blast_result
cat blast_result | head -n 10 | cut -f 2 > top_hits
blastdbcmd -db $db -entry_batch top_hits > sequences
"""
}
正如脚本教程部分所解释的,字符串可以通过使用单引号或双引号定义,多行字符串可以由三个单引号或三个双引号字符定义。
它们之间有一个微妙但重要的区别。与Bash类似,以双引号 " 分隔的字符串支持变量替换,而以单引号 ' 分隔的字符串则不支持变量替换(脚本块习惯使用三个双引号)。在上面的代码片段中,$db变量被管道脚本中某处定义的实际值所替换。
Warning
由于Nextflow对字符串中的变量替换使用相同的Bash语法,因此需要仔细管理它们,这取决于您是想在Nextflow上下文中计算变量,还是在Bash环境执行中计算变量。
当需要访问脚本中的系统环境变量时,有两个选项。第一种选择与使用单引号字符串定义脚本块一样简单。例如:
process printPath {
'''
echo The path is: $PATH
'''
}
这种解决方案的缺点是,您将无法在脚本块中访问管道脚本上下文中定义的变量。
要解决这个问题,请使用双引号字符串定义脚本,并在系统环境变量前加上反斜杠\字符进行转义,如下面的示例所示:
process doOtherThings {
"""
blastp -db \$DB -query query.fa -outfmt 6 > blast_result
cat blast_result | head -n $MAX | cut -f 2 > top_hits
blastdbcmd -db \$DB -entry_batch top_hits > sequences
"""
}
在本例中,DB变量必须存在于脚本执行环境中,Bash解释器将用实际值替换它。
Tip
或者,您可以使用Shell块定义,它允许脚本同时包含Bash和Nextflow变量,而无需对第一个变量进行转义。
Scripts à la carte
在默认情况下,Nextflow将流程脚本解释为Bash脚本,但您并不局限于此。
您可以使用您最喜欢的脚本语言(例如Perl、Python、Ruby、R等),甚至可以将它们混合在同一管道中。
管道可以由执行非常不同任务的进程组成。使用Nextflow,您可以选择更适合指定流程执行的任务的脚本语言。例如,对于某些进程,R可能比Perl更有用,而在其他进程中,你可能需要使用Python,因为它提供了对库或API的更好访问,等等。
要使用Bash以外的脚本,只需使用相应的shebang声明启动流程脚本。例如:
# 这段代码运行时注意perl/python版本
process perlStuff {
"""
#!/usr/bin/perl
print 'Hi there!' . '\n';
"""
}
process pyStuff {
"""
#!/usr/bin/python
x = 'Hello'
y = 'world!'
print "%s - %s" % (x,y)
"""
}
Tip
由于解释器二进制文件的实际位置可以跨平台更改,为了使脚本更易于移植,明智的做法是使用env shell命令后跟解释器的名称,而不是解释器的绝对路径。因此,例如,Perl脚本的shebang声明类似于:#!/usr/bin/env perl,而不是上面管道片段中的那个。
Conditional scripts
复杂的流程脚本可能需要评估输入参数的条件,或者使用传统的流控制语句(例如,if、switch等)来执行特定的脚本命令,这取决于当前的输入配置。
只需在脚本块前面加上关键字script:,流程脚本就可以包含条件语句。通过这样做,解释器将把下列语句作为一个必须返回要执行的脚本字符串的代码块来计算。使用起来要比解释起来容易得多,例如:
seq_to_align = ...
mode = 'tcoffee'
process align {
input:
file seq_to_aln from sequences
script:
if( mode == 'tcoffee' )
"""
t_coffee -in $seq_to_aln > out_file
"""
else if( mode == 'mafft' )
"""
mafft --anysymbol --parttree --quiet $seq_to_aln > out_file
"""
else if( mode == 'clustalo' )
"""
clustalo -i $seq_to_aln -o out_file
"""
else
error "Invalid alignment mode: ${mode}"
}
在上面的例子中,进程将根据mode参数的值执行脚本片段。默认情况下,它将执行tcoffee命令,将模式变量更改为mafft或clustalo值,然后执行其他分支。
Template
流程脚本可以通过使用模板文件外部化,这些模板文件可以跨不同的流程重用,并独立于整个管道执行进行测试。
模板只是一个shell脚本文件,Nextflow可以使用如下所示的模板函数来执行它:
process template_example {
input:
val STR from 'this', 'that'
script:
template 'my_script.sh'
}
Nextflow在模板目录中查找my_script.sh模板文件,该模板文件必须存在于Nextflow脚本文件所在的文件夹中(任何其他位置都可以通过使用绝对模板路径提供)。
模板脚本可以包含可由底层系统执行的任何代码段。例如:
#!/bin/bash
echo "process started at `date`"
echo $STR
:
echo "process completed"
Tip
注意,当脚本作为Nextflow模板运行时,美元字符($)被解释为Nextflow变量占位符,而当单独运行时,它被计算为Bash变量。这对于自主测试脚本非常有用,例如独立于Nextflow执行。您只需要为脚本中存在的每个Nextflow变量提供一个Bash环境变量。例如,可以在shell终端中输入以下命令来执行上面的脚本:STR='foo' bash templates/my_script.sh
Shell
shell块是一个字符串语句,它定义了进程执行的shell命令来执行它的任务。它是对Script定义的一种替代,但有一个重要的区别,它使用感叹号!字符作为Nextflow变量的占位符,以代替通常的美元字符。
process myTask {
input:
val str from 'Hello', 'Hola', 'Bonjour'
shell:
'''
echo User $USER says !{str}
'''
}
在上面的简单示例中,$USER变量由Bash解释器管理,而!{str}则作为进程输入变量由Nextflow管理。
Note
- Shell 脚本定义需要使用单引号 ' 分隔的字符串。 当使用双引号 " 分隔的字符串时,美元变量像往常一样被解释为 Nextflow 变量。请参阅String interpolation。
- 感叹号前缀变量总是需要用大括号括起来,即 !{str} 是一个有效变量,而 !str 被忽略。
- Shell 脚本支持使用文件模板机制。 相同的规则适用于脚本模板中定义的变量。
Native execution
Nextflow流程可以执行本机代码,而不是前面所示的系统脚本。
这意味着不需要指定要作为字符串脚本执行的process命令,而可以通过提供一个或多个语言语句来定义它,就像在管道脚本的其余部分中所做的那样。只需用exec:关键字启动脚本定义块,例如:
x = Channel.from( 'a', 'b', 'c')
process simpleSum {
input:
val x
exec:
println "Hello Mr. $x"
}
打印结果:
Hello Mr. b
Hello Mr. a
Hello Mr. c
输入(Inputs)
Nextflow流程彼此隔离,但可以通过通道在它们之间发送值。输入块定义了流程期望从哪个通道接收数据。一次只能定义一个输入块,并且它必须包含一个或多个输入声明。
输入块遵循如下语法:
input:
<input qualifier> <input name> [from <source channel>] [attributes]
输入定义以输入限定符和输入名称开始,然后是关键字from和接收输入的实际通道。最后,可以指定一些输入可选属性。
Note
当输入名与通道名相同时,可以省略声明中的from部分。
输入限定符(qualifier)声明要接收的数据类型。Nextflow使用这些信息来应用与每个限定符关联的语义规则,并根据目标执行平台(网格、云等)适当地处理它。
可用的限定符如下表所示:
限定符 | 语意 |
---|---|
val | 允许您通过流程脚本中的名称访问接收的输入值 |
env | 允许您使用接收到的值来设置命名为指定输入名称的环境变量 |
file | 允许您将接收到的值作为文件处理,并在执行上下文中适当地分段 |
path | 允许您将接收到的值作为路径处理,在执行上下文中正确地分段文件 |
stdin | 允许您将接收到的值转发到进程的stdin特殊文件 |
tuple | 允许您处理一组具有上述限定符之一的输入值 |
each | 允许您为输入集合中的每个条目执行流程 |
泛型值输入
val限定符允许您接收任何类型的数据作为输入。可以在进程脚本中使用指定的输入名访问它,如下面的示例所示:
num = Channel.from( 1, 2, 3 )
process basicExample {
input:
val x from num
"echo process job $x"
}
在上面的示例中,进程被执行三次,每次从通道num接收一个值并用于处理脚本。因此,它会得到如下所示的输出:
process job 3
process job 1
process job 2
Note
通道保证条目按照发送时的顺序交付——但是,由于流程是以并行方式执行的,因此不能保证条目按照接收时的顺序被处理。事实上,在上面的示例中,值3是在其他值之前处理的。
当val与接收数据的通道同名时,可以省略from部分。因此,上面的例子可以写成如下所示:
num = Channel.from( 1, 2, 3 )
process basicExample {
input:
val num
"echo process job $num"
}
文件输入
文件限定符允许在流程执行上下文中处理文件值。这意味着Nextflow将把它放到流程执行目录中,并且可以通过使用输入声明中指定的名称在脚本中访问它。例如:
proteins = Channel.fromPath( '/some/path/*.fa' )
process blastThemAll {
input:
file query_file from proteins
"blastp -query ${query_file} -db nr"
# 这里只有一条命令要执行,所以不需要三个双引号,一个双引号即可
}
在上面的例子中,所有后缀为.fa
的文件都通过通道proteins
发送。然后,进程接收这些文件,并对每个文件执行BLAST查询。
当文件输入名与通道名相同时,可以省略输入声明中的from部分。因此,上面的例子可以写成:
proteins = Channel.fromPath( '/some/path/*.fa' )
process blastThemAll {
input:
file proteins
"blastp -query $proteins -db nr"
}
值得注意的是,在上面的示例中,文件系统中文件的名称没有touch,你可以访问文件甚至不知道它的名字,因为你可以参考脚本过程中通过使用变量的名字在输入文件中指定参数声明。
在某些情况下,您的任务需要使用名称固定的文件,而不必随实际提供的文件一起更改。在这种情况下,您可以通过在输入文件参数声明中指定name
属性来指定它的名称,如下面的示例所示:
input:
file query_file name 'query.fa' from proteins
或者使用更短的语法:
input:
file 'query.fa' from proteins
使用这个,前面的例子可以重写为如下所示:
proteins = Channel.fromPath( '/some/path/*.fa' )
process blastThemAll {
input:
file 'query.fa' from proteins
"blastp -query query.fa -db nr"
}
在这个例子中,进程接收到的每个文件都以query.fa
的名字暂存到不同的执行上下文中(即执行作业的文件夹),并启动一个独立的进程执行。
Tip
这允许您在不同的时间执行process命令,而不必担心文件名更改。换句话说,Nextflow帮助您编写自包含并由执行环境解耦的管道任务。这也是为什么您应该尽可能避免在管道进程中使用绝对或相对路径引用文件的原因。
多个文件输入
进程可以声明一个通道作为输入文件,该通道发出一组值,而不是一个简单的值。
在这种情况下,由输入文件参数定义的脚本变量将保存文件列表。您可以像前面所示的那样使用它,引用列表中的所有文件,或者使用通常的方括号符号访问特定的条目。
当在输入参数中定义目标文件名,并且进程接收到文件集合时,文件名将被数字后缀附加,表示其在列表中的序号位置。例如:
fasta = Channel.fromPath( "/some/path/*.fa" ).buffer(size:3)
process blastThemAll {
input:
file 'seq' from fasta
"echo seq*"
}
能够看到输出:
seq1 seq2 seq3
seq1 seq2 seq3
...
目标输入文件名可以包含*和?通配符,可用于控制分段文件的名称。下表显示了如何根据接收的输入集合的基数替换通配符。
基数 | 文件名pattern | 分段文件名示例 |
---|---|---|
any | * | 目的位置所有文件 |
1 | file*.ext | file.ext |
1 | file?.ext | file1.ext |
1 | file??.ext | file01.ext |
many | file*.ext | file1.ext, file2.ext, file3.ext, .. |
many | file?.ext | file1.ext, file2.ext, file3.ext, .. |
many | file??.ext | file01.ext, file02.ext, file03.ext, .. |
many | dir/* | dir子目录下所有文件 |
many | dir??/* | 子目录中所有文件,创建在一个渐进索引的子目录中,例如dir01/, dir02/等 |
many | dir/ | 与上类似 |
下面的片段展示了如何在输入文件声明中使用通配符:
fasta = Channel.fromPath( "/some/path/*.fa" ).buffer(size:3)
process blastThemAll {
input:
file 'seq?.fa' from fasta
"cat seq1.fa seq2.fa seq3.fa"
}
Note
根据指定的模式重写输入文件名是一种额外的特性,而不是必须的。文件的输入部分中引入的普通文件输入构造对于多个文件的集合也是有效的。要处理多个保留原始文件名的输入文件,可以使用*通配符作为名称模式或变量标识符。
动态输入文件名
当使用name file子句或短字符串表示法指定输入文件名时,允许在文件名字符串中使用其他输入值作为变量。例如:
process simpleCount {
input:
val x from species
file "${x}.fa" from genomes
"""
cat ${x}.fa | grep '>'
"""
}
在上面的示例中,输入文件名是通过使用x输入值的当前值设置的。
这允许将输入文件以与当前执行上下文一致的名称暂存到脚本工作目录中。
Tip
在大多数情况下,您不需要使用动态文件名,因为每个进程都在自己的私有临时目录中执行,并且Nextflow会自动将输入文件暂存到该目录中。这保证了具有相同名称的输入文件不会相互覆盖。
类型为path的输入
path
输入限定符是由Nextflow 19.10.0版本引入的,它是file
限定符的临时替代,因此它与上面描述的输入file
的语法和语义向后兼容。
file
限定符和path
限定符之间的重要区别是,第一个限定符期望作为输入接收的值是文件对象。当输入是不同类型时,它会自动转换为字符串并将其保存到临时文件中。这在某些情况下可能很有用,但在大多数常见情况下却很棘手。
path
限定符将字符串值解释为输入文件的路径位置,并自动转换为文件对象。
process foo {
input:
path x from '/some/data/file.txt'
"""
your_command --in $x
"""
}
Note
所提供的输入值应该表示绝对路径位置,即字符串值必须以/字符或支持的URI协议为前缀,如file://, http://, s3://等,它不能包含特殊字符(例如\n等)。
stageAs选项允许您控制如何在任务工作目录中对文件进行命名,提供一个特定的名称或名称模式,如前面“多个文件输入”部分所述:
process foo {
input:
path x, stageAs: 'data.txt' from '/some/data/file.txt'
"""
your_command --in data.txt
"""
}
Tip
当使用Nextflow 19.10.0或更高版本时,路径限定符应该优先于文件来处理流程输入文件。
类型为'stdin'的输入
stdin输入限定符允许您将从通道接收到的值转发到进程执行的命令的标准输入。例如:
str = Channel.from('hello', 'hola', 'bonjour', 'ciao').map { it+'\n' }
process printAll {
input:
stdin str
"""
cat -
"""
}
输出结果如下
hola
bonjour
ciao
hello
类型为'env'的输入
env限定符允许您根据从通道接收的值在流程执行上下文中定义环境变量。例如:
str = Channel.from('hello', 'hola', 'bonjour', 'ciao')
process printEnv {
input:
env HELLO from str
'''
echo $HELLO world!
'''
}
输出为
hello world!
ciao world!
bonjour world!
hola world!
类型为'tuple'的输入
tuple限定符允许您在单个参数定义中对多个参数进行分组。当进程在输入中接收到需要单独处理的元组值时,它会很有用。元组中的每个元素都与元组定义的对应元素相关联。例如:
values = Channel.of( [1, 'alpha'], [2, 'beta'], [3, 'delta'] )
process tupleExample {
input:
tuple val(x), file('latin.txt') from values
"""
echo Processing $x
cat - latin.txt > copy
"""
}
在上面的示例中,tuple参数用于定义值x和文件latin.txt,该文件将从相同的通道接收值。
在元组声明中,可以使用以下限定符定义项:val、env、file和stdin。
通过应用以下替换规则可以使用更短的表示法:
long | short |
---|---|
val(x) | x |
file(x) | (not supported) |
file(‘name’) | ‘name’ |
file(x:’name’) | x:’name’ |
stdin | ‘-‘ |
env(x) | (not supported) |
因此,前面的例子可以重写为:
values = Channel.of( [1, 'alpha'], [2, 'beta'], [3, 'delta'] )
process tupleExample {
input:
tuple x, 'latin.txt' from values
"""
echo Processing $x
cat - latin.txt > copy
"""
}
文件名可以动态定义,如动态输入文件名部分所述。
输入中继器
each限定符允许您在每次接收到新数据时,为集合中的每个项重复执行流程。例如:
sequences = Channel.fromPath('*.fa')
methods = ['regular', 'expresso', 'psicoffee']
process alignSequences {
input:
file seq from sequences
each mode from methods
"""
t_coffee -in $seq -mode $mode > result
"""
}
在上面的示例中,每当进程接收到序列文件作为输入时,它都会执行三个任务,使用mode参数的不同值运行T-coffee比对。当您需要为给定的一组参数重复相同的任务时,这是非常有用的。
自从版本0.25+输入重复器可以应用到文件。例如:
sequences = Channel.fromPath('*.fa')
methods = ['regular', 'expresso']
libraries = [ file('PQ001.lib'), file('PQ002.lib'), file('PQ003.lib') ]
process alignSequences {
input:
file seq from sequences
each mode from methods
each file(lib) from libraries
"""
t_coffee -in $seq -mode $mode -lib $lib > result
"""
}
Note
当声明多个重复器时,将对它们的每个组合执行流程。
在后面的例子中,序列通道发出的任何序列输入文件都执行6个比对,3个比对每个库文件使用regular方法,另外3个比对总是使用expresso方法。
Hint
如果需要在n元组元素(而不是简单的值或文件)上重复执行进程,请根据需要创建一个通道,将输入值组合在一起,以触发进程多次执行。在这方面,请参阅组合运算符、交叉运算符和相位运算符。
理解多输入通道是如何工作的
processes的一个关键特性是能够处理来自多个通道的输入。
当两个或多个通道声明为process中输入时,process将停止,直到有一个完整的输入配置ie。它从所有声明为输入的通道接收输入值。
当验证此条件时,它将使用来自各个通道的输入值,并生成任务执行,然后重复相同的逻辑,直到一个或多个通道没有更多内容。
这意味着通道值将依次使用,第一个空通道将导致流程停止执行,即使其他通道中有其他值。
例如:
process foo {
echo true
input:
val x from Channel.from(1,2)
val y from Channel.from('a','b','c')
script:
"""
echo $x and $y
"""
}
进程foo被执行了两次,因为第一个输入通道只提供了两个值,因此c元素被丢弃。它打印:
1 and a
2 and b
Warning
当使用值通道或单例通道时,应用了不同的语义。
这种channel是由 Channel.value factory方法或当流程输入在from子句中指定简单值时隐式地使用。
根据定义,Value channel绑定到单个值,可以无限次地读取该值而不消耗其内容。
这些属性使得当值通道与一个或多个(队列)通道混合时,它不会影响只依赖于其他通道的进程终止,并且它的内容会重复应用。
为了更好地理解这种行为,请将前面的示例与下面的示例进行比较:
process bar {
echo true
input:
val x from Channel.value(1)
val y from Channel.from('a','b','c')
script:
"""
echo $x and $y
"""
}
上面的代码片段执行bar进程三次,因为第一个输入是一个值通道,因此它的内容可以根据需要读取多次。进程终止由第二通道的内容决定。它打印:
1 and a
1 and b
1 and c
个人理解是放在process外面定义成列表,然后在process中调用则能够将所有情况执行
输出(Outputs)
输出声明块允许您定义流程用来发送产生的结果的通道。一次只能定义一个输出块,并且它必须包含一个或多个输出声明。
输出块遵循如下语法:
output:
<output qualifier> <output name> [into <target channel>[,channel,..]] [attribute [,..]]
输出定义以输出qualifier和输出name开始,然后是关键字into和输出所经过的一个或多个通道。最后,可以指定一些可选属性。
Note
当输出名称与通道名称相同时,可以省略声明中的into部分。
可以在输出声明块中使用的限定符如下表所示:
Qualifier | 语义 |
---|---|
val | 通过输出通道发送具有指定名称的变量 |
file | 通过输出通道发送由进程生成的具有指定名称的文件 |
path | 通过输出通道发送由进程生成的具有指定名称的文件(替换file)。 |
env | 通过输出通道发送在流程环境中定义的变量和指定的名称 |
stdout | 通过输出通道发送执行的进程标准输出 |
tuple | 通过同一个输出通道发送多个值 |
输出值
val限定符允许您输出在脚本上下文中定义的值。在一个常见的使用场景中,这是一个在输入声明块中定义的值,如下面的示例所示:
methods = ['prot','dna', 'rna']
process foo {
input:
val x from methods
output:
val x into receiver
"""
echo $x > file
"""
}
receiver.view { "Received: $it" }
有效的输出值包括值字面值、输入值标识符、流程范围内可访问的变量和值表达式。例如:
process foo {
input:
file fasta from 'dummy'
output:
val x into var_channel
val 'BB11' into str_channel
val "${fasta.baseName}.out" into exp_channel
script:
x = fasta.name
"""
cat $x > file
"""
}
输出文件
文件限定符允许您通过指定的通道输出进程生成的一个或多个文件。例如:
process randomNum {
output:
file 'result.txt' into numbers
'''
echo $RANDOM > result.txt
'''
}
numbers.subscribe { println "Received: " + it.text }
在上面的示例中,该过程在执行时创建了一个名为result.txt的文件,其中包含一个随机数。由于在输出之间声明了使用相同名称的file参数,当任务完成时,该文件将通过numbers通道发送。声明与输入通道相同的下游流程将能够接收它。
Note
如果指定为输出的通道之前没有在管道脚本中声明,则输出声明本身将隐式创建该通道。
多个文件输出
当输出文件名包含*或?通配符,它被解释为一个全局路径匹配器。这允许您将多个文件捕获到一个列表对象中,并将它们作为单独的发射输出。例如:
process splitLetters {
output:
file 'chunk_*' into letters
'''
printf 'Hola' | split -b 1 - chunk_
'''
}
letters
.flatMap()
.subscribe { println "File: ${it.name} => ${it.text}" }
打印结果:
File: chunk_aa => H
File: chunk_ab => o
File: chunk_ac => l
File: chunk_ad => a
Note
在上面的例子中,操作符flatMap用于将letters通道发出的文件列表转换为单独发出每个文件对象的通道。
关于glob模式行为的一些警告:
- 输入文件不包括在可能的匹配列表中。
- Glob模式匹配文件和目录路径。
- 当一个双星模式**用于跨目录追索时,只有文件路径匹配,即目录不包括在结果列表中。
Warning
尽管匹配glob输出声明的输入文件不包含在结果输出通道中,但这些文件仍然可以从任务暂存目录转移到目标任务工作目录。因此,为了避免不必要的文件复制,建议在定义输出文件时避免使用松散的通配符,例如file ''。相反,使用前缀或后缀命名法来限制匹配文件的集合,例如file 'prefix_.sorted.bam'。
默认情况下,通道将发送与指定glob模式匹配的所有文件作为唯一(列表)项。通过在输出文件声明中添加mode flatten属性,还可以将每个文件作为单独的项发出。
通过使用mode属性,可以将前面的示例重写为如下所示:
process splitLetters {
output:
file 'chunk_*' into letters mode flatten
'''
printf 'Hola' | split -b 1 - chunk_
'''
}
letters .subscribe { println "File: ${it.name} => ${it.text}" }
Warning
选项模式从19.10.0版本开始已弃用。在下游过程中使用operator collect代替。
在下面的链接中阅读更多关于glob语法的信息
What is a glob
文件名动态输出
当需要动态表示输出文件名时,可以使用动态求值字符串来定义它,该字符串引用在输入声明块或脚本全局上下文中定义的值。例如:
process align {
input:
val x from species
file seq from sequences
output:
file "${x}.aln" into genomes
"""
t_coffee -in $seq > ${x}.aln
"""
}
在上面的示例中,每次执行流程时都会生成一个对齐文件,该文件的名称取决于x输入的实际值。
Tip
输出文件的管理是使用Nextflow时非常常见的误解。 使用其他工具通常需要将输出文件组织成某种目录结构或保证唯一的文件名方案,以便结果文件不会相互覆盖,并且它们可以被下游任务唯一地引用。
使用Nextflow,在大多数情况下,您不需要关心命名输出文件,因为每个任务都在自己唯一的临时目录中执行,因此不同任务生成的文件永远不会相互覆盖。 此外,元数据可以通过使用元组输出限定符与输出相关联,而不是将它们包含在输出文件名中。
总而言之,尽可能使用带有静态名称的输出文件而不是动态名称的输出文件,因为它会产生更简单、更可移植的代码。
输出路径
路径输出限定符path
是由Nextflow版本19.10.0引入的,它是文件输出限定符file
的临时替换,因此它与上面描述的输入限定符file
的语法和语义向后兼容。
path
优于文件限定符file
的主要优点是,它允许指定大量输出来精细控制输出文件。
名称 | 描述 |
---|---|
glob | 当为true时,指定的名称被解释为glob模式(默认:true) |
hidden | 当为真时,隐藏文件包含在匹配的输出文件中(默认:false) |
followLinks | 当返回true时,目标文件代替任何匹配的符号链接(默认:true) |
type | 返回路径的类型,可以是file, dir或any(默认为any,如果指定的文件名模式包含** -双星号-则为file) |
maxDepth | 要访问的目录级别的最大数目(默认:没有限制) |
includeInputs | 当为真时,将包含任何匹配输出文件glob模式的输入文件 |
Warning
限定符file
将冒号(:)解释为路径分隔符,因此文件'foo:bar'同时捕获文件foo和bar。限定符path
将其解释为一个纯文件名字符,因此输出定义路径'foo:bar'捕获名称为foo:bar的输出文件。
Tip
当使用Nextflow 19.10.0或更高版本时,path
限定符应该优先于file
来处理流程输出文件。
'stdout'输出特殊文件
stdout限定符允许您捕获执行过程的stdout输出,并通过输出参数声明中指定的通道发送它。例如:
process sayHello {
output:
stdout ch
"""
echo Hello world!
"""
}
ch.view { print "I say.. $it" }
在上面的例子中,ch代表了一个保存流程输出的任意通道变量。
'env'输出
env限定符允许您捕获在进程执行环境中定义的变量,并通过输出参数声明中指定的通道发送它:
process myTask {
output:
env FOO into target
script:
'''
FOO=$(ls -la)
'''
}
target.view { "directory content: $it" }
值的'tuple'输出
tuple限定符允许您将多个值发送到单个通道。当您需要将同一进程的多次执行的结果组合在一起时,该特性非常有用,如下面的示例所示:
query_ch = Channel.fromPath '*.fa'
species_ch = Channel.from 'human', 'cow', 'horse'
process blast {
input:
val species from query_ch
file query from species_ch
output:
tuple val(species), file('result') into blastOuts
script:
"""
blast -db nr -query $query > result
"""
}
在上面的示例中,对接收到的每一对物种和查询执行BLAST任务。当任务完成时,一个包含物种值的新元组和文件结果被发送到blastOuts通道。
元组声明可以包含前面描述的下列限定符的任意组合:val、file和stdout。
Tip
默认情况下,变量标识符被解释为值,而字符串字面量被解释为文件,因此可以使用如下所示的简短表示法重写上述输出元组。
output:
tuple species, 'result' into blastOuts
可选输出
在大多数情况下,流程将生成添加到输出通道的输出。但是,在某些情况下,流程不生成输出是有效的。在这些情况下,可以将可选的true添加到输出声明中,它告诉Nextflow如果没有创建声明的输出,就不要让流程失败。
output:
file("output.txt") optional true into outChannel
在本例中,该过程通常会生成一个output.txt文件,但在文件合法丢失的情况下,该过程不会失败。outChannel仅由那些生成output.txt的进程填充。
When
when声明允许您定义一个条件,该条件必须经过验证才能执行流程。这可以是任何计算布尔值的表达式。
根据各种输入和参数的状态来启用/禁用流程执行是很有用的。例如:
process find {
input:
file proteins
val type from dbtype
when:
proteins.name =~ /^BB11.*/ && type == 'nr'
script:
"""
blastp -query $proteins -db nr
"""
}
网友评论