Как я могу прочитать параметры командной строки из сценария R?

281

У меня есть R-скрипт, для которого я хотел бы иметь возможность предоставлять несколько параметров командной строки (а не значения параметров жесткого кода в самом коде). Скрипт работает на Windows.

Я не могу найти информацию о том, как прочитать параметры, указанные в командной строке, в мой R-скрипт. Я был бы удивлен, если это не может быть сделано, поэтому, возможно, я просто не использую лучшие ключевые слова в моем поиске Google ...

Есть указатели или рекомендации?

monch1962
источник
вам нужно указать расположение исполняемого файла

Ответы:

209

Ответ Дирка здесь - все, что вам нужно. Вот минимальный воспроизводимый пример.

Я сделал два файла: exmpl.batи exmpl.R.

  • exmpl.bat:

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

    В качестве альтернативы, используя Rterm.exe:

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

    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 с некоторым сюжетом
  • exmpl.batch со всем, что было сделано

Вы также можете добавить переменную окружения %R_Script%:

"C:\Program Files\R-3.0.2\bin\RScript.exe"

и использовать его в своих пакетных сценариях как %R_Script% <filename.r> <arguments>

Различия между RScriptи Rterm:

Marek
источник
127

Несколько моментов:

  1. Параметры командной строки доступны через commandArgs(), так что смотрите help(commandArgs)для обзора.

  2. Вы можете использовать Rscript.exeна всех платформах, включая Windows. Это поддержит commandArgs(). littler может быть портирован на Windows, но сейчас живет только на OS X и Linux.

  3. В CRAN есть два пакета дополнений - getopt и optparse, которые были написаны для анализа командной строки.

Редактирование в ноябре 2015: появились новые альтернативы, и я искренне рекомендую docopt .

Дирк Эддельбюттель
источник
2
и есть argparse
gkcn
92

Добавьте это в начало вашего скрипта:

args<-commandArgs(TRUE)

Затем вы можете ссылаться на аргументы, переданные как args[1]и args[2]т. Д.

Тогда беги

Rscript myscript.R arg1 arg2 arg3

Если ваши аргументы являются строками с пробелами, заключите их в двойные кавычки.

Хриши Миттал
источник
7
Это работало только когда я использовал args <-commandArgs (TRUE) (обратите внимание на верхний регистр A).
Энди Вест
тебе нужен --args перед arg1?
Филколборн,
@philcolbourn Нет
Chris_Rands
15

Попробуйте библиотеку (getopt) ... если вы хотите, чтобы все было лучше. Например:

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),"\n"));
    q();
}
Эрик Аронесты
источник
11

вам нужно немного (произносится «маленький г»)

Дирк будет около 15 минут, чтобы уточнить;)

JD Long
источник
11

Поскольку optparseв ответах уже упоминалось несколько раз, и он предоставляет исчерпывающий набор для обработки командной строки, вот краткий упрощенный пример того, как его можно использовать, предполагая, что входной файл существует:

script.R:

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 выходы

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"

Мегатрон
источник
7

В bash вы можете создать командную строку следующим образом:

$ 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 на «10», и это значение выбирается commandArgsи подается в него args[2], а команда диапазона x=1:10выполняется R успешно и т. Д. И т. Д.

TTW
источник
4

К вашему сведению: есть функция args (), которая извлекает аргументы функций R, которые не следует путать с вектором аргументов с именем args

Тим
источник
1
Это почти наверняка не так. Только функции могут маскировать функции. Создание переменной с тем же именем, что и у функции, не маскирует функцию. Обратитесь к этому вопросу и ответам: stackoverflow.com/q/6135868/602276
Андри
Правда, это не маскирует это. В общем, я стараюсь избегать именования функций и переменных с именами, которые уже существуют в R.
Тим
1

Если вам нужно указать опции с флагами (например, -h, --help, --number = 42 и т. Д.), Вы можете использовать пакет optparse (вдохновленный Python): http://cran.r-project.org /web/packages/optparse/vignettes/optparse.pdf .

По крайней мере, так я понимаю ваш вопрос, потому что я нашел этот пост, когда искал эквивалент bash getopt, или perl Getopt, или python argparse и optparse.

TheBinturonGggh
источник
1

Я просто собрал красивую структуру данных и цепочку обработки для генерации такого переключения, библиотеки не нужны. Я уверен, что это будет реализовано много раз, и наткнулся на эту тему в поисках примеров - думал, что я скинуться

Мне даже не были нужны флаги (единственный флаг здесь - режим отладки, создающий переменную, которую я проверяю как условие запуска функции ниже по потоку if (!exists(debug.mode)) {...} else {print(variables)}). Приведенные lapplyниже операторы проверки флага выдают то же самое, что и:

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

где args- переменная, считываемая из аргументов командной строки (символьный вектор, эквивалентный тому, c('--debug','--help')когда вы, например, задаете их)

Его можно использовать для любого другого флага, и вы избегаете всех повторений, и никаких библиотек, поэтому нет никаких зависимостей:

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="\n\n")

# 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, очевидно, желателен для любого серьезного скрипта, но код с минимальной функциональностью тоже иногда хорош.

Образец вывода:

$ Rscript check_mail.Rscript --help
--debug Печатать переменные, а не выполнять функцию XYZ ...

-h --help Показать определения флага
Луи Мэддокс
источник