NextFlow用法2--Scripts

2019-07-11  本文已影响0人  京古

Nextflow Scripts

Nextflow脚本语言是Groovy编程语言的扩展。Groovy是Java虚拟机的强大编程语言。Nextflow语法专门用于以声明方式简化计算流水线的编写。

Nextflow可以执行任何Groovy代码或使用任何库用于JVM平台。

有关Groovy编程语言的详细说明,请参考以下链接:

· Groovy用户指南

· Groovy备忘单

· Groovy in Action

您可以在下面找到Nextflow脚本语言中使用的最重要的语言结构的速成课程。

警告

Nextflow UTF-8用作源文件和应用程序文件的默认文件字符编码。使用UTF-8您喜欢的文本编辑器编辑Nextflow脚本时,请务必使用编码。

1.Language basics

1.1 Hello world

使用print或println方法即可:

println "Hello, World!"

两者之间的唯一区别是该println方法隐式地将新行字符附加到打印字符串。

1.2 变量

要定义变量,只需为其赋值:

x = 1
println x
x = new java.util.Date()
println x
x = -3.1499392
println x
x = false
println x
x = "Hi"
println x

1.3 Lists

可以通过将列表项放在方括号中来定义List对象:

myList **=** [1776, **-**1, 33, 99, 0, 928734928763]

您可以使用方括号表示法访问列表中的给定项目(索引从0开始):

println myList[0]

为了获得列表的长度,请使用以下size方法:

println myList**.**size()

详细了解列表:

· Groovy列表教程

· Groovy List SDK

· Java List SDK

1.4 Maps

Maps 用于存储关联数组或词典。它们是异构的命名数据的无序集合:

scores = [ "Brett":100, "Pete":"Did not finish", "Andrew":86.87934 ]

请注意,存储在map中的每个值可以是不同的类型。Brett是一个整数,Pete是一个字符串,Andrew是一个浮点数。

我们可以通过两种主要方式访问map中的值:

println scores["Pete"]

println scores.Pete

要向map添加数据或修改map,语法类似于向列表添加值:

scores["Pete"] = 3

scores["Cedric"] = 120

详细了解map:

· Groovy Maps教程

· Groovy Map SDK

· Java Map SDK

1.5 Multiple assignment

数组或列表对象可用于一次分配多个变量:

(a, b, c) = [10, 20, 'foo']

assert a == 10 && b == 20 && c == 'foo'

赋值运算符左侧的三个变量由列表中的相应项初始化。

1.6 条件执行

任何编程语言最重要的特性之一是能够在不同条件下执行不同的代码。最简单的方法是使用if构造:

x = Math.random()

if( x < 0.5 ) {

println "You lost."

}else {

println "You won!"

}

1.7 Strings

可以通过用单引号或双引号('或"字符)括起文本来定义字符串:

println "he said 'cheese' once"

println 'he said "cheese!" again'

字符串可以与+以下内容连接:

a = "world"

print "hello " + a + "\n"

1.8 String interpolation

单引号和双引号字符串之间存在重要差异:双引号字符串支持变量插值,而单引号字符串则不支持。

实际上,双引号字符串可以包含任意变量的值,方法是在其名称前加上字符,或者使用{expression}语法表示任何表达式的值,类似于Bash / shell脚本:

foxtype = 'quick'

foxcolor = ['b', 'r', 'o', 'w', 'n']

println "The $foxtype ${foxcolor.join()} fox"

x = 'Hello'

println '$x + $y'

/* 结果 */

The quick brown fox

$x + $y

1.9 Multi-line strings

跨越多行的文本块可以通过用三个单引号或双引号分隔来定义:

text = """

hello there James

how are you today?

    """

注意:

与之前一样,双引号内的多行字符串支持变量插值,而单引号多行字符串则不支持。

与在Bash / shell脚本中一样,在带有\字符的多行字符串中终止一行会阻止新行字符将该行与后面的行分开:

myLongCmdline **=** """ blastp         \

                -in $input_query       \

                -out $output_file      \

                -db $blast_database    \

                -html

                """

result = myLongCmdline.execute().text

在前面的示例中,blastp的-in和-out,-db和-html开关及其参数实际上是一行。

2 Closures

简而言之,闭包是一个代码块,可以作为参数传递给函数。因此,您可以定义一大块代码,然后将其传递,就像它是字符串或整数一样。

更正式地说,您可以创建定义为第一类对象的函数。

square  =  {  it  *  it  }

表达式周围的大括号告诉脚本解释器将此表达式视为代码。it标识符是一个隐式变量,表示调用时传递给函数的值。

编译完成后,函数对象将被分配给square变量,就像之前显示的任何其他变量赋值一样。现在我们可以这样做:

println square(9)

并获得值81。

我们可以将函数square作为参数传递给其他函数或方法。一些内置函数将这样的函数作为参数。一个例子是collect列表上的方法:

[ 1, 2, 3, 4 ].collect(square)

这个表达式说:创建一个值为1,2,3和4的数组,然后调用它的collect方法,传入我们上面定义的闭包。该collect方法遍历数组中的每个项目,调用定义好的闭包,然后将结果放入新数组中,从而产生:

[ 1, 4, 9, 16 ]

有关可以使用闭包作为参数调用的更多方法,请参阅 :
http://docs.groovy-lang.org/latest/html/groovy-jdk/

默认情况下,闭包会调用一个参数it,但您也可以创建具有多个自定义命名参数的闭包。例如,该方法Map.each()可以采用带有两个参数的闭包,它将键绑定到值,并为该键中的每个键值对关联值Map。在这里,我们使用明显的变量名称key并value在我们的闭包中:

printMapClosure ={ key, value ->

    println "$key = $value"}

[ "Yue": "Wu", "Mark": "Williams", "Sudha": "Kumari" ].each(printMapClosure)

打印:

Yue=Wu

Mark=Williams

Sudha=Kumari

封闭物还有另外两个重要特征。首先,它可以访问定义它的范围内的变量,以便它可以与它们进行交互。

其次,闭包可以以匿名方式定义,这意味着它没有给出名称,并且在需要使用它的地方定义。

作为显示这两个功能的示例,请参阅以下代码片段:

myMap = ["China": 1, "India": 2, "USA": 3]

result = 0
myMap.keySet().each( { result += myMap[it] } )

println result

Groovy文档中了解有关闭包的更多信息:http://groovy-lang.org/closures.html .

3. Regular expressions

正则表达式是瑞士军刀级别的文本处理方法。它们为程序员提供了匹配和提取字符串模式的能力。

通过 ~/pattern/ 语法 =~ 和 ==~ 运算符可以使用正则表达式。

使用 =~ 检查给定模式是否在字符串中的任何位置发生:

assert 'foo' =~ /foo/       // return TRUE

assert 'foobar' =~ /foo/    // return TRUE

使用 ==~ 检查字符串是否与给定的正则表达式模式完全匹配。

assert 'foo' ==~ /foo/       // return TRUE

assert 'foobar' ==~ /foo/    // return FALSE

值得注意的是,~ 运算符从给定的字符串创建Java Pattern对象,而 =~ 运算符创建Java Matcher对象。

x = ~/abc/

println x.class

// prints java.util.regex.Pattern

y = 'some string' =~ /abc/

println y.class

// prints java.util.regex.Matcher

正则表达式支持从Java导入。Java的正则表达式语言和API在Pattern Java文档中有记录

你可能也对这篇文章感兴趣:Groovy:

https://web.archive.org/web/20170621185113/http://www.naleid.com/blog/2008/05/19/dont-fear-the-regexp

3.1 String replacement

要替换给定字符串中的模式出现次数,请使用replaceFirst和replaceAll方法:

x = "colour".replaceFirst(/ou/, "o")

println x

// prints: color

y = "cheesecheese".replaceAll(/cheese/, "nice")

println y

// prints: nicenice

3.2 Capturing groups

您可以匹配包含组的模式。首先使用 =~ 运算符创建匹配器对象。然后,您可以索引匹配器对象以查找匹配项:matcher[0]返回表示字符串中正则表达式的第一个匹配项的列表。第一个列表元素是与整个正则表达式匹配的字符串,其余元素是与每个组匹配的字符串。

以下是它的工作原理:

programVersion = '2.7.3-beta'

m = programVersion =~ /(\d+)\.(\d+)\.(\d+)-?(.+)/

assert m[0] ==  ['2.7.3-beta', '2', '7', '3', 'beta']

assert m[0][1] == '2'

assert m[0][2] == '7'

assert m[0][3] == '3'

assert m[0][4] == 'beta'

应用一些语法糖,你可以在一行代码中做同样的事情:

programVersion = '2.7.3-beta'

(full, major, minor, patch, flavor) = (programVersion =~ /(\d+)\.(\d+)\.(\d+)-?(.+)/)[0]

println full    // 2.7.3-beta

println major   // 2

println minor   // 7

println patch   // 3

println flavor  // beta

3.3 Removing part of a string

您可以使用正则表达式模式删除部分String值。找到的第一个匹配项将替换为空字符串:

// define the regexp pattern

wordStartsWithGr = ~/(?i)\s+Gr\w+/

// apply and verify the result

('Hello Groovy world!' - wordStartsWithGr) == 'Hello world!'

('Hi Grails users' - wordStartsWithGr) == 'Hi users'

从字符串中删除第一个5个字符的单词:

assert ('Remove first match of 5 letter word' - ~/\b\w{5}\b/) == 'Remove  match of 5 letter word'

从字符串中删除带有尾随空格的第一个数字:

assert ('Line contains 20 characters' - ~/\d+\s+/) == 'Line contains characters'

4. Files and I/O

要访问和使用文件,请使用该file方法,该方法在给定文件路径字符串的情况下返回文件系统对象:

myFile = file('some/path/to/my_file.file')

该file方法可以引用文件或目录,具体取决于文件系统中字符串路径引用的内容。

使用通配符 * 时 ? ,[] 和 {} ,该参数被解释为glob路径匹配器,并且该file方法返回一个列表对象,其中包含名称与指定模式匹配的文件的路径,如果找不到匹配项则返回空列表:

listOfFiles = file('some/path/*.fa')

注意

glob模式中的两个星号(**)与 * 类似,但匹配文件系统路径中的任意数量的目录组件。

默认情况下,通配符与目录或隐藏文件不匹配。例如,如果要在结果列表中包含隐藏文件,请添加可选参数hidden:

listWithHidden = file('some/path/*.fa', hidden: true)

以下是file可用选项:

名称 描述
glob -- 当true时,将字符*,?,[]和{}解释为glob通配符,否则将它们作为普通字符处理(默认值:true)
type 返回的路径类型,要么file,dir或any(默认值:file)
hidden -- 当true时,能返回隐藏文件(默认值:false)
maxDepth -- 要访问的最大目录级别数(默认值:无限制)
followLinks -- 当true时,可以遍历符号链接,否则将它们视为文件(默认:true)
checkIfExists -- 当true时,若抛出指定路径不存在则抛出异常(默认值:false)

注意

如果您是Java极客,您将有兴趣知道该file方法返回一个Path对象,它允许您使用Java程序中常用的方法。

另请参见:Channel.fromPath

4.1 Basic read/write

给定一个文件变量,使用file前面示例中显示的方法声明,读取文件就像获取文件text属性的值一样简单,该属性将文件内容作为字符串值返回:

print myFile.text

同样,您只需将字符串值保存到文件的text属性即可将其保存到文件中:

myFile.text = 'Hello world!'

注意

现有文件在被操作时,其原始内容会被覆盖,该操作也隐式创建不存在的文件。

为了在不删除现有内容的情况下将字符串值附加到文件,您可以使用以下append方法:

myFile.append('Add this line\n')

或者使用左移运算符,这是一种将文本内容附加到文件的更惯用的方法:

myFile << 'Add a line more\n'

二进制数据可以以相同的方式处理,只使用file的bytes属性而不是text。因此,以下示例读取文件并将其内容作为字节数组返回:

binaryContent = myFile.bytes

或者您可以将字节数组数据缓冲区保存到文件中,只需编写:

myFile.bytes = binaryBuffer

警告

上述方法在单个变量或缓冲区中一次读写所有文件内容。因此,在处理需要更高内存效率的大文件时,不建议使用它们,例如逐行读取文件或使用固定大小的缓冲区。

4.2 Read a file line by line

为了逐行读取文本文件,您可以使用readLines()文件对象提供的方法,该方法将文件内容作为字符串列表返回:

myFile = file('some/my_file.txt')

allLines  = myFile.readLines()

for( line: allLines ) {

println line

}

这也可以用更惯用的语法编写:

file('some/my_file.txt')

    .readLines()

    .each{ println it }

注意

该readLines()方法一次性读取所有文件内容并返回包含所有行的列表。因此,请勿使用它来读取大文件。

要处理大文件,请使用该方法eachLine,该方法一次只读取一行到内存中:

count = 0
myFile.eachLine {  str ->

        println "line ${count++}: $str"

    }

4.3 Advanced file reading operations

类Reader和InputStream可以操作文本和二进制文件.

该newReader方法为给定文件创建一个Reader对象,允许您将内容读取为单个字符,行或字符数组:

myReader = myFile.newReader()

String line

while( line = myReader.readLine() ) {

println line

}

myReader.close()

newReader方法为给定文件创建一个Reader对象,允许您将内容读取为单个字符,行或字符数组::

myReader = myFile.newReader()

String line

while( line = myReader.readLine() ) {

println line

}

myReader.close()

newInputStream和withInputStream方法的工作方式类似。主要区别在于它们创建了一个用于编写二进制数据的InputStream对象。

以下是从文件中读取的最重要方法:
"待补充"

阅读ReaderInputStream类的Java文档,以了解有关可用于从文件读取数据的方法的更多信息。

上一篇下一篇

猜你喜欢

热点阅读