Передача аргументов командной строки в R CMD BATCH

103

Я использую R CMD BATCH my_script.Rтерминал для выполнения Rсценария. Сейчас я нахожусь в той точке, где я хотел бы передать аргумент команде, но у меня возникли некоторые проблемы с его работой. Если я это сделаю, R CMD BATCH my_script.R blablaто он blablaстанет выходным файлом, а не будет интерпретироваться как аргумент, доступный для выполняемого сценария R.

Я пробовал, Rscript my_script.R blablaчто, кажется, правильно передается blablaв качестве аргумента, но тогда я не получаю my_script.Routвыходной файл, с которым я получаю R CMD BATCH(мне нужен .Routфайл). Хотя я мог перенаправить вывод вызова Rscriptна имя файла по своему выбору, я не получал бы входные команды R, включенные в файл, как это R CMD BATCHпроисходит в .Routфайле.

Итак, в идеале я ищу способ передать аргументы сценарию R, выполняемому через этот R CMD BATCHметод, хотя был бы доволен подходом, использующим, Rscriptесли есть способ заставить его создать сопоставимый .Routфайл.

Брайс Томас
источник

Ответы:

115

Мне кажется, что это что- 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чтобы произвести .Routфайл подобного производства R CMD BATCH. Один из способов - создать небольшой сценарий R - назовите его RscriptEcho.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

который будет выполняться myScript.Rс предоставленными аргументами и принимать чередующиеся ввод, вывод и сообщения в одноименный объект .Rout.

Edit2:
вы можете запустить Rscript подробно и поместить подробный вывод в файл.

Rscript --verbose myScript.R 5 100 > myScript.Rout
Джош О'Брайен
источник
4
Мне тоже кажется, что R CMD BATCHэто реликвия. Что мне в нем нравится, так это то, что он создает .Routфайл, который включает не только выходные данные сценария, но также чередует входные команды / комментарии из .Rфайла сценария, создавшего этот вывод.
Bryce Thomas
1
Я слышу тебя. Это было (я думаю, все еще остается!) Приятным аспектом R CMD BATCH.
Джош О'Брайен
5
но я думаю , что вы можете сделать лучше , чем R CMD BATCHс knitr, например , Rscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(вы можете заменить stitchс stitch_rhtmlили stitch_rmd, и вам необходимо установить knitrиз Github , так как я только что нашел ошибку в stitch...)
Yihui Се
7
Просто чтобы добавить мою 0,02, также легко использовать перенаправление с терминала. Например, Rscript myfile.R > path/to/mylog.Routвместо вывода на стандартный вывод (экран) вывод файла сохраняется в вашем .Routфайле.
Джеймс Прингл
4
Чтобы добавить к @JamesPringle, я часто хочу, чтобы мой вывод выводился как на экран (для мониторинга в реальном времени), так и в файл (для просмотра позже). Я делаюRscript myfile.R | tee mylog.Rout
Гейзенберг
26

Попробовав описанные здесь варианты, я нашел этот пост от Forester в r-bloggers. Я думаю, что это чистый вариант для рассмотрения.

Я поместил его код сюда:

Из командной строки

$ 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)

В test.out

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

Спасибо Forester !

Алекс А.
источник
Важно отметить, что если аргументы имеют символьный тип, нет необходимости использовать одинарные / двойные кавычки. Например: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d 01
Как упоминалось в сообщении Forester, --argsэто ключ. Он также работает с R --no-save --no-restore --args a=1 < test.RиR --no-save --no-restore < test.R --args a=1
Дэйв
Есть ли способ передать аргументы из командной строки в --args? Допустим, мы хотим выполнить цикл for в командной строке, а затем отправить его в строке --args.
user2809432 09
9

Вам нужно поставить аргументы перед my_script.Rи использовать- аргументы, например

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.
Ихуэй Се
источник
2
Я замечаю, что если я делаю это таким образом и в сценарии use, args <- commandArgs(FALSE)а затем print args, я получаю все аргументы, включая те, которые мне не принадлежат, например --restore, --saveи т.д. Если я использую, commandArgs(TRUE)я не получаю аргументов вообще. Есть ли способ получить только мои собственные дополнительные аргументы? --argsвыглядит многообещающе, но мне не удалось заставить его работать ...
Брайс Томас
Вы должны считать аргументы с конца (например, размер-2, размер-1, размер) - ваш всегда будет в конце.
ynka
9

В вашем сценарии 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 
user1563570
источник
4

Я добавляю ответ, потому что считаю, что однострочное решение всегда хорошо! Поверх вашего 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"
КлементУолтер
источник
0

Вот еще один способ обработки аргументов командной строки, используя R CMD BATCH. Мой подход, основанный на предыдущем ответе здесь , позволяет вам указывать аргументы в командной строке и в вашем сценарии R указывать некоторые или все значения по умолчанию.

Вот R-файл, который я назвал 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= 2и b= c(2,5,6). Но я мог бы, скажем, опустить bи добавить еще один аргумент c:

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

Тогда в R у нас будет a= 2, b= 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)))
Дагрему
источник