R语言接受命令行参数的三种方式

作者: 白菜代码小推车 | 来源:发表于2019-08-22 18:28 被阅读0次

    R语言接受命令行参数的三种方式

    最近要用一下R的命令行,但是发现命令行参数不是很友好,就总结了一下目前常用的R的命令行参数的接受方法。

    平常我们使用R语言的时候常常都是在交互界面中一步一步更改运行,所以一般用不到命令来执行,但有时候对于批量运行或者某种情况下数据较大,直接在Rstudio中运行卡顿,在把代码提前调试好后后续使用命令行可能更好,另外一半我们编写好的脚本搭建pipeline的时候需要命令行执行,这个时候就必须要命令行来实现了。

    R接受命令的参数有三个常见的方法commandArgs()getopt()OptionParser(),其中第一个是R自带的函数,后面两个分别来自包getoptoptparse

    运行命令行脚本

    在之前了解一下R语言的命令行方式,下面在windows的cmd中还是Mac或者Linux的终端中的命令行用法都是这样的。[options]是R脚本解释器的参数,[args]是脚本的参数。如果是Linux或者Mac的话可以省略Rscipt,在脚本第一行加上shebang#!/usr/bin/Rscript

    Rscript [options] file [args]
    

    下面是一个R脚本示例test.R

    print("Hello R!")
    

    在终端中运行

    Rscript test.R
    

    成功输出

    [1] "Hello R!"
    

    1. commandArgs()

    这是个R内置命令,和perl@ARGV或者和pythonsys.argv类似,就是将来自于命令的参数存入向量(数组)中。但是与perlpython的不同,它的前面几个元素不是命令行的参数,先尝试打印一下这个参数是怎样的。

    下面是一个测试脚本test.R

    # commandArgs()就返回一个包含参数信息的向量
    args <- commandArgs()
    print(args)
    

    开始测试

    Rscript test_args.R Hello R
    

    输出为

    [1] "C:\\PROGRA~1\\R\\R-35~1.2\\bin\\x64\\Rterm.exe"
    [2] "--slave"
    [3] "--no-restore"
    [4] "--file=test_args.R"
    [5] "--args"
    [6] "Hello"
    [7] "R"
    

    参数解释:

    位置 说明 示例
    1 R所在的路径 C:\PROGRA1\R\R-351.2\bin\x64\Rterm.exe
    2 Rscript的参数 --slave
    3 Rscript的参数 --no-restore
    4 运行R脚本的路径 --file=test_args.R
    5 脚本参数flag --args
    6 第一个参数 Hello
    7 第二个参数 R

    那么就是说输入的参数是从第6个开始(注意!R的索引与python或者perl不同,它是从1开始的。)

    其实对于参数的位置是可变的,在R所在路径R脚本的路径这两个参数之间是Rscript的参数,这些参数的数量是可变的(其实这里也就是是按照顺序的Rscript的参数,后面的脚本其实也就是一个参数而已,这里看来和python或者perl是差不多的。)

    2和3这两个参数虽然我们没有输入,但是是作为Rscript的默认参数的。
    
    参数索引  1       2       3            4                  5      6     7
             Rscript --slave --no-restore --file=test_args.R --args Hello R
    

    这样一来就会导致R脚本的参数的索引不固定,针对这种情况,你也可以添加一个参数来削掉R脚本参数之前的参数了。

    args <- commandArgs(trailingOnly = TRUE)
    print(args)
    

    输出为

    [1] "Hello"
    [2] "R"
    

    这样R脚本的参数就从1开始了。

    但是这样对于参数解析的顺序是需要的,也就是说脚本接受的参数的输入需要严格按照顺序来,有时候为了区分参数使用这个命令其实是不方便的。使用特定的flag来区分参数是需要,当然R也是有相应的包来做这些事情的。

    2. getopt

    在使用之前需要安装对应的包:

    install.packages("getopt")
    

    这个包的getopt()函数使用方法是

    getopt(spec = NULL, opt = commandArgs(TRUE),command = get_Rscript_filename(), usage = FALSE,debug = FALSE)
    
    • spec:这个参数需要一个矩阵,这个矩阵描述了接受参数的flag以及参数的形式等等信息
    第一列 第二列 第三列 第四列 第五列
    说明 参数的长名称(多个字符) 参数的短名称(一个字符) 这个flag对应的参数形式(0表示flag不接受参数;1表示可接可不接;2表示必须接参数) 参数的类型(logical;integer;double;complex;character;numeric) 注释信息
    示例 "first_arg" "f" 2 "double" "This arg is the first arguments"
    • opt:表示参数的来源,一般都是使用默认的,也就是commandArgs()接受

    • usage:用法,就是说明帮助信息,默认为FALSE

    下面是一个示例,将下列代码存到test.R文件中:

    library(getopt)
    
    # 首先将第一个参数的具体信息进行描述
    # 每行五个,第五个可选,也就是说第五列可以不写
    # byrow 按行填充矩阵的元素
    # ncol  每行填充五个元素
    spec <- matrix(
      c("first",  "f", 2, "integer", "This is first!",
        "second", "s", 1, "character",  "This is second!",
        "third",  "t", 2, "double",  "This is third!",
        "help",   "h", 0, "logical",  "This is Help!"),
      byrow=TRUE, ncol=5)
    
    # 使用getopt方法
    opt <- getopt(spec=spec)
    
    # opt实际上就是一个列表,直接使用$来索引到对应的参数的值
    print(opt$first)
    print(opt$second)
    print(opt$third)
    

    在命令行执行

    Rscript test.R -f 123 -t 1.1 -s Hello
    

    输出为:

    [1] 123
    [1] "Hello"
    [1] 1.1
    

    但是这里如果参数输出不正确的时候并不能弹出详细的帮助信息,下面增加一些信息就可以得到相应的帮助信息了

    library(getopt)
    
    # 首先将第一个参数的具体信息进行描述
    spec <- matrix(
    # 每行五个,第五个可选,也就是说第五列可以不写
    # byrow 按行填充矩阵的元素
    # ncol  每行填充五个元素
      c("first",  "f", 2, "integer", "This is first!",
        "second", "s", 1, "character",  "This is second!",
        "third",  "t", 2, "double",  "This is third!",
        "help",   "h", 0, "logical",  "This is Help!"),
      byrow=TRUE, ncol=5)
    
    # 使用getopt方法,注意这里的usage默认是关闭的,这里不能打开
    opt <- getopt(spec=spec)
    
    # 这个时候需要将usage参数打开,这样getpot()就会返回一个特定写法的帮助文件
    # 当然你也可以自己写帮助,然后将if判断语句中的打印的信息换成你自己定义的帮助信息
    if( !is.null(opt$help) || is.null(opt$first) || is.null(opt$third) ){
        # ... 这里你也可以自定义一些东放在里面
        cat(paste(getopt(spec=spec, usage = T), "\n"))
        quit()
    }
    
    # opt实际上就是一个列表,直接使用$来索引到对应的参数的值
    print(opt$first)
    print(opt$second)
    print(opt$third)
    

    命令行执行

    Rscript test.R -h
    

    输出为:

    Usage: test_args.R [-[-first|f] [<integer>]] [-[-second|s] <character>] [-[-third|t] [<double>]] [-[-help|h]]
        -f|--first     This is first!
        -s|--second    This is second!
        -t|--third     This is third!
        -h|--help      This is Help!
    

    解析参数的包不止一个,R也不例外,这里也有另外一个包也是干同样的事情的,但是它的用法与上面的getopt包有一定差别。

    3. optparse

    使用之前安装包

    install.packages("optparse")
    

    其中的方法OptionParser()的用法为:

    OptionParser(usage = "usage: %prog [options]", option_list = list(),
      add_help_option = TRUE, prog = NULL, description = "",
      epilogue = "")
    

    其中最重要的参数是option_list,这个参数接受一个列表,这个列表是被用来描述命令参数的解析方式的。

    下面是一个例子,将下列代码存到test.R文件中:

    library(optparse)
    
    # 描述参数的解析方式
    option_list <- list(
      make_option(c("-f", "--first"), type = "integer", default = FALSE,
                  action = "store", help = "This is first!"
      ),
      make_option(c("-s", "--second"), type = "character", default = FALSE,
                  action = "store", help = "This is second!"
      ),
      make_option(c("-t", "--third"), type = "double", default = FALSE,
                  action = "store", help = "This is third!"
      ),
      # make_option(c("-h", "--help"), type = "logical", default = FALSE,
      #             action = "store_TRUE", help = "This is Help!"
      # )
    )
    
    # 解析参数
    opt = parse_args(OptionParser(option_list = option_list, usage = "This Script is a test for arguments!"))
    
    print(opt)
    

    注意,这个模块不用加上-h的flag,不然会报错:

    Error in parse_args(OptionParser(option_list = option_list)) :
      Error in getopt(spec = spec, opt = args) :
      redundant long names for flags (column 1 of spec matrix).
    

    其实从这个报错信息可以看出来这个模块其实还是调用了getopt模块

    直接运行

    Rscript test.R -f 10 -s Hello -t 1.1
    

    结果:

    $first      
    [1] 10      
                
    $second     
    [1] "Hello" 
                
    $third      
    [1] 1.1     
                
    $help       
    [1] FALSE
    

    如果加上-h

    Usage: This Script is a test for arguments!     
                                                    
                                                    
    Options:                                        
            -f FIRST, --first=FIRST                 
                    This is first!                  
                                                    
            -s SECOND, --second=SECOND              
                    This is second!                 
                                                    
            -t THIRD, --third=THIRD                 
                    This is third!                  
                                                    
            -h, --help                              
                    Show this help message and exit 
    

    这里Usage后面跟的信息时候在OptionParser中usage方法指定。

    试了试这三个方式,第一个是最简洁的,如果你的脚本输出入参数很少(只有一两个的话),那就采用commandArgs()方法吧,使用轻便;其他两个模块干的活很相似,但是我感觉第三个optparse在接受参数的描述上与python的optparse模块的风格更加像一些,好像模块名也是一样的,里面的参数都很像,所以用过python的会对这个模块很熟悉,另外就是自动生成的帮助文档相对于getopt的来说更加友好一些,生成的解析命令行的描述不容易出错。但是就风格上,getopt更加轻便,解析命令行的参数的描述就是一个矩阵,看起来更加清晰一些。

    如需转载,请注明来源:https://www.jianshu.com/p/8797972113d7

    参考

    说明,本文部分参考青萍,你好的博客,部分经过整理与修改。

    相关文章

      网友评论

        本文标题:R语言接受命令行参数的三种方式

        本文链接:https://www.haomeiwen.com/subject/aieosctx.html