向 R CMD BATCH 传递命令行参数

我一直在从终端使用 R CMD BATCH my_script.R来执行 R脚本。我现在想要向命令传递一个参数,但是在让它工作时遇到了一些问题。如果执行 R CMD BATCH my_script.R blabla,那么 blabla将成为输出文件,而不是被解释为可用于正在执行的 R 脚本的参数。

我已经尝试了 Rscript my_script.R blabla,它似乎正确地将 blabla作为参数传递,但是我没有得到用 R CMD BATCH得到的 my_script.Rout输出文件(我想要 .Rout文件)。虽然我可以将对 Rscript的调用的输出重定向到我选择的文件名,但是我不会像 R CMD BATCH.Rout文件中那样获得文件中包含的 R 输入命令。

So, ideally, I'm after a way to pass arguments to an R script being executed via the R CMD BATCH method, though would be happy with an approach using Rscript if there is a way to make it produce a comparable .Rout file.

143034 次浏览

You need to put arguments before my_script.R and use - on the arguments, e.g.

R CMD BATCH -blabla my_script.R

在这种情况下,commandArgs()将接收 -blabla作为字符串。详细信息请参阅帮助:

$ R CMD BATCH --help
Usage: R CMD BATCH [options] infile [outfile]


Run R non-interactively with input from infile and place output (stdout
and stderr) to another file.  If not given, the name of the output file
is the one of the input file, with a possible '.R' extension stripped,
and '.Rout' appended.


Options:
-h, --help        print short help message and exit
-v, --version     print version info and exit
--no-timing           do not report the timings
--            end processing of options


Further arguments starting with a '-' are considered as options as long
as '--' was not encountered, and are passed on to the R process, which
by default is started with '--restore --save --no-readline'.
See also help('BATCH') inside R.

我的印象是,R CMD BATCH是一个有点遗迹。在任何情况下,最新的 Rscript可执行文件(可在所有平台上使用)和 commandArgs()使得处理命令行参数非常容易。

作为一个例子,这里有一个小脚本——称之为 "myScript.R":

## myScript.R
args <- commandArgs(trailingOnly = TRUE)
rnorm(n=as.numeric(args[1]), mean=as.numeric(args[2]))

下面是从命令行调用它的过程

> Rscript myScript.R 5 100
[1]  98.46435 100.04626  99.44937  98.52910 100.78853

编辑:

并不是说我会推荐它,但是... 使用 source()sink()的组合,您可以让 Rscript生成类似于 R CMD BATCH生成的 .Rout文件。一种方法是创建一个小的 R 脚本——调用 itRscriptEcho.R——您可以直接使用 Rscript 调用它。它可能看起来像这样:

## RscriptEcho.R
args <- commandArgs(TRUE)
srcFile <- args[1]
outFile <- paste0(make.names(date()), ".Rout")
args <- args[-1]


sink(outFile, split = TRUE)
source(srcFile, echo = TRUE)

要执行实际的脚本,您需要执行以下操作:

Rscript RscriptEcho.R myScript.R 5 100
[1]  98.46435 100.04626  99.44937  98.52910 100.78853

which will execute myScript.R with the supplied arguments and sink interleaved input, output, and messages to a uniquely named .Rout.

编辑2:
You can run Rscript verbosely and place the verbose output in a file.

Rscript --verbose myScript.R 5 100 > myScript.Rout

在您的 R 脚本,称为 test.R:

args <- commandArgs(trailingOnly = F)
myargument <- args[length(args)]
myargument <- sub("-","",myargument)
print(myargument)
q(save="no")

从命令行运行:

R CMD BATCH -4 test.R

您的输出文件 test.Rout 将显示参数 4已成功传递到 R:

cat test.Rout


> args <- commandArgs(trailingOnly = F)
> myargument <- args[length(args)]
> myargument <- sub("-","",myargument)
> print(myargument)
[1] "4"
> q(save="no")
> proc.time()
user  system elapsed
0.222   0.022   0.236

在尝试了这里描述的选项之后,我在 r-blogger 中找到了来自 Forester 的 这篇文章。我认为这是一个明智的选择。

I put his code here:

从命令行

$ R CMD BATCH --no-save --no-restore '--args a=1 b=c(2,5,6)' test.R test.out &

Test.R

##First read in the arguments listed at the command line
args=(commandArgs(TRUE))


##args is now a list of character vectors
## First check to see if arguments are passed.
## Then cycle through each element of the list and evaluate the expressions.
if(length(args)==0){
print("No arguments supplied.")
##supply default values
a = 1
b = c(1,1,1)
}else{
for(i in 1:length(args)){
eval(parse(text=args[[i]]))
}
}


print(a*2)
print(b*3)

测试,出局

> print(a*2)
[1] 2
> print(b*3)
[1]  6 15 18

Thanks to Forester!

我添加一个答案,因为我认为一行解决方案总是好的! 在 myRscript.R文件的顶部,添加以下代码行:

eval(parse(text=paste(commandArgs(trailingOnly = TRUE), collapse=";")))

然后提交你的剧本,比如:

R CMD BATCH [options] '--args arguments you want to supply' myRscript.R &

例如:

R CMD BATCH --vanilla '--args N=1 l=list(a=2, b="test") name="aname"' myscript.R &

然后:

> ls()
[1] "N"    "l"    "name"

Here's another way to process command line args, using R CMD BATCH. My approach, which builds on 这里有一个更早的答案, lets you specify arguments at the command line and, in your R script, give some or all of them default values.

Here's an R file, which I name test.R:

defaults <- list(a=1, b=c(1,1,1)) ## default values of any arguments we might pass


## parse each command arg, loading it into global environment
for (arg in commandArgs(TRUE))
eval(parse(text=arg))


## if any variable named in defaults doesn't exist, then create it
## with value from defaults
for (nm in names(defaults))
assign(nm, mget(nm, ifnotfound=list(defaults[[nm]]))[[1]])


print(a)
print(b)

在命令行中,如果我键入

R CMD BATCH --no-save --no-restore '--args a=2 b=c(2,5,6)' test.R

那么在 R 里面,我们有 a = 2b = c(2,5,6)。但是,我可以省略 b,并添加另一个参数 c:

R CMD BATCH --no-save --no-restore '--args a=2 c="hello"' test.R

然后在 R 中,我们有 a = 2b = c(1,1,1)(默认值) ,和 c = "hello"

最后,为了方便起见,我们可以将 R 代码封装在一个函数中,只要我们对环境保持谨慎:

## defaults should be either NULL or a named list
parseCommandArgs <- function(defaults=NULL, envir=globalenv()) {
for (arg in commandArgs(TRUE))
eval(parse(text=arg), envir=envir)


for (nm in names(defaults))
assign(nm, mget(nm, ifnotfound=list(defaults[[nm]]), envir=envir)[[1]], pos=envir)
}


## example usage:
parseCommandArgs(list(a=1, b=c(1,1,1)))