如何从R脚本中读取命令行参数?

How can I read command line parameters from an R script?

我有一个R脚本,我想为它提供几个命令行参数(而不是代码本身的硬编码参数值)。该脚本在Windows上运行。

我找不到有关如何将命令行上提供的参数读取到R脚本中的信息。如果不能做到,我会很惊讶,所以也许我在谷歌搜索中没有使用最好的关键词…

有什么建议吗?


德克的答案就是你所需要的一切。这是一个最小的可重复的例子。

我做了两份文件:exmpl.batexmpl.R

  • exmpl.bat

    1
    2
    3
    4
    set R_Script="C:\Program Files
    -3.0.2\bin
    Script.exe"
    %R_Script% exmpl.R 2010-01-28 example 100 > exmpl.batch 2>&1

    或者,使用Rterm.exe

    1
    2
    3
    4
    set R_TERM="C:\Program Files
    -3.0.2\bin\i386
    term.exe"
    %R_TERM% --no-restore --no-save --args 2010-01-28 example 100 < exmpl.R > exmpl.batch 2>&1
  • exmpl.R

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    options(echo=TRUE) # if you want see commands in output file
    args <- commandArgs(trailingOnly = TRUE)
    print(args)
    # trailingOnly=TRUE means that only your arguments are returned, check:
    # print(commandArgs(trailingOnly=FALSE))

    start_date <- as.Date(args[1])
    name <- args[2]
    n <- as.integer(args[3])
    rm(args)

    # Some computations:
    x <- rnorm(n)
    png(paste(name,".png",sep=""))
    plot(start_date+(1L:n), x)
    dev.off()

    summary(x)

将两个文件保存在同一目录中,并启动exmpl.bat。结果你会得到:

  • example.png有一些图
  • 完成了所有的工作

您还可以添加一个环境变量%R_Script%

1
2
3
"C:\Program Files
-3.0.2\bin
Script.exe"

在批处理脚本中使用它作为%R_Script%

RScriptRterm的区别:

  • RScript的语法比较简单
  • RScript自动选择X64上的架构(详见R安装管理2.6子架构)
  • 如果要将命令写入输出文件,RScript需要.r文件中的options(echo=TRUE)

几点:

  • 命令行参数为可通过commandArgs()访问,因此关于概述。

  • 您可以在所有平台(包括Windows)上使用Rscript.exe。它将支持commandArgs()。Littler可以移植到Windows,但现在只能在OS X和Linux上运行。

  • cran上有两个附加包——getopt和optparse——都是为命令行解析而编写的。

  • 2015年11月编辑:出现了新的备选方案,我衷心推荐Docopt。


    将此添加到脚本顶部:

    1
    args<-commandArgs(TRUE)

    然后,您可以将传递的参数称为args[1]args[2]等。

    然后运行

    1
    Rscript myscript.R arg1 arg2 arg3

    如果参数是包含空格的字符串,请用双引号括起来。


    尝试库(getopt)…如果你想要更好的话。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    spec <- matrix(c(
            'in'     , 'i', 1,"character","file from fastq-stats -x (required)",
            'gc'     , 'g', 1,"character","input gc content file (optional)",
            'out'    , 'o', 1,"character","output filename (optional)",
            'help'   , 'h', 0,"logical",  "this help"
    ),ncol=5,byrow=T)

    opt = getopt(spec);

    if (!is.null(opt$help) || is.null(opt$in)) {
        cat(paste(getopt(spec, usage=T),"
    "));
        q();
    }

    你需要一点(读作"小R")。

    德克将在大约15分钟内赶到现场进行详细说明;)


    由于在答案中多次提到optparse,并且它提供了一个用于命令行处理的综合工具包,下面是一个简单的示例,说明如何使用它,假设输入文件存在:

    脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    library(optparse)

    option_list <- list(
      make_option(c("-n","--count_lines"), action="store_true", default=FALSE,
        help="Count the line numbers [default]"),
      make_option(c("-f","--factor"), type="integer", default=3,
        help="Multiply output by this number [default %default]")
    )

    parser <- OptionParser(usage="%prog [options] file", option_list=option_list)

    args <- parse_args(parser, positional_arguments = 1)
    opt <- args$options
    file <- args$args

    if(opt$count_lines) {
      print(paste(length(readLines(file)) * opt$factor))
    }

    给定一个任意文件blah.txt有23行。

    在命令行上:

    Rscript script.R -h输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Usage: script.R [options] file


    Options:
            -n, --count_lines
                    Count the line numbers [default]

            -f FACTOR, --factor=FACTOR
                    Multiply output by this number [default 3]

            -h, --help
                    Show this help message and exit

    Rscript script.R -n blah.txt输出[1]"69"

    Rscript script.R -n -f 5 blah.txt输出[1]"115"


    在bash中,您可以构建如下命令行:

    1
    2
    3
    4
    5
    6
    7
    8
    $ z=10
    $ echo $z
    10
    $ Rscript -e"args<-commandArgs(TRUE);x=args[1]:args[2];x;mean(x);sd(x)" 1 $z
     [1]  1  2  3  4  5  6  7  8  9 10
    [1] 5.5
    [1] 3.027650
    $

    可以看到变量$z被bash shell替换为"10",该值由commandArgs接收并送入args[2],范围命令x=1:10由r成功执行等。


    仅供参考:有一个函数args(),它检索r函数的参数,不要与名为args的参数向量混淆。


    我只是将一个好的数据结构和处理链组合在一起,以生成这种交换行为,不需要库。我确信它将被多次实现,并且在这个线程中找到了一些例子——我认为我会插手进来。

    我甚至不需要特别的标志(这里唯一的标志是调试模式,创建一个变量,作为启动下游函数if (!exists(debug.mode)) {...} else {print(variables)})的条件进行检查)。下面检查lapply语句的标志生成如下:

    1
    2
    if ("--debug" %in% args) debug.mode <- T
    if ("-h" %in% args ||"--help" %in% args)

    其中,args是从命令行参数中读取的变量(例如,提供这些参数时,相当于c('--debug','--help')的字符向量)

    它对于任何其他标志都是可重用的,您可以避免所有重复,并且没有库,因此没有依赖项:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    args <- commandArgs(TRUE)

    flag.details <- list(
    "debug" = list(
      def ="Print variables rather than executing function XYZ...",
      flag ="--debug",
      output ="debug.mode <- T"),
    "help" = list(
      def ="Display flag definitions",
      flag = c("-h","--help"),
      output ="cat(help.prompt)") )

    flag.conditions <- lapply(flag.details, function(x) {
      paste0(paste0('"',x$flag,'"'), sep =" %in% args", collapse =" ||")
    })
    flag.truth.table <- unlist(lapply(flag.conditions, function(x) {
      if (eval(parse(text = x))) {
        return(T)
      } else return(F)
    }))

    help.prompts <- lapply(names(flag.truth.table), function(x){
    # joins 2-space-separatated flags with a tab-space to the flag description
      paste0(c(paste0(flag.details[x][[1]][['flag']], collapse=" "),
      flag.details[x][[1]][['def']]), collapse="\t")
    } )

    help.prompt <- paste(c(unlist(help.prompts),''),collapse="

    ")

    # The following lines handle the flags, running the corresponding 'output' entry in flag.details for any supplied
    flag.output <- unlist(lapply(names(flag.truth.table), function(x){
      if (flag.truth.table[x]) return(flag.details[x][[1]][['output']])
    }))
    eval(parse(text = flag.output))

    注意,在flag.details中,命令存储为字符串,然后用eval(parse(text = '...'))进行计算。optparse显然对任何严肃的脚本都是可取的,但是最小功能代码有时也很好。

    样品输出:

    1
    2
    3
    4
    $ Rscript check_mail.Rscript --help
    --debug Print  variables rather than executing function XYZ...

    -h  --help  Display flag definitions

    如果需要使用标记指定选项(如-h、-help、-number=42等),则可以使用r包optparse(源自python):http://cran.r-project.org/web/packages/optparse/vignettes/optparse.pdf.

    至少我是这样理解你的问题的,因为我在寻找与bash getopt、perl getopt或python argparse和optparse等效的东西时找到了这篇文章。