Como posso ler os parâmetros da linha de comando de um script R?


281

Eu tenho um script R para o qual gostaria de poder fornecer vários parâmetros de linha de comando (em vez de valores de parâmetro de código fixo no próprio código). O script é executado no Windows.

Não consigo encontrar informações sobre como ler os parâmetros fornecidos na linha de comando no meu script R. Eu ficaria surpreso se isso não puder ser feito, então talvez eu não esteja usando as melhores palavras-chave na minha pesquisa no Google ...

Alguma indicação ou recomendação?


você precisa definir o local do executável do rscript

Respostas:


209

A resposta de Dirk aqui é tudo que você precisa. Aqui está um exemplo mínimo reproduzível.

Eu criei dois arquivos: exmpl.bate 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

    Como alternativa, usando 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)

Salve os dois arquivos no mesmo diretório e inicie exmpl.bat. No resultado, você obterá:

  • example.png com algum enredo
  • exmpl.batch com tudo o que foi feito

Você também pode adicionar uma variável de ambiente %R_Script%:

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

e use-o em seus scripts em lote como %R_Script% <filename.r> <arguments>

Diferenças entre RScripte Rterm:

  • Rscript possui sintaxe mais simples
  • Rscriptescolhe automaticamente a arquitetura em x64 (consulte R Instalação e administração, 2.6 Subarquiteturas para obter detalhes)
  • Rscriptprecisa options(echo=TRUE)no arquivo .R se você deseja gravar os comandos no arquivo de saída

127

Alguns pontos:

  1. Os parâmetros da linha de comando são acessíveis via commandArgs(), portanto, veja help(commandArgs)uma visão geral.

  2. Você pode usar Rscript.exeem todas as plataformas, incluindo Windows. Vai apoiar commandArgs(). littler poderia ser portado para o Windows, mas agora vive apenas no OS X e Linux.

  3. Existem dois pacotes complementares no CRAN - getopt e optparse - que foram escritos para análise de linha de comando.

Editar em novembro de 2015: Novas alternativas apareceram e eu recomendo sinceramente o docopt .


2
e há argparse
gkcn

92

Adicione isso ao topo do seu script:

args<-commandArgs(TRUE)

Em seguida, você pode consultar os argumentos passados como args[1], args[2]etc.

Então corra

Rscript myscript.R arg1 arg2 arg3

Se seus argumentos forem cadeias de caracteres com espaços, coloque-as entre aspas duplas.


7
Isso funcionou apenas quando eu usei args <-commandArgs (TRUE) (observe o A maiúsculo).
Andy West

você precisa --args antes do arg1?
Philcolbourn

@philcolbourn Não
Chris_Rands

15

Experimente a biblioteca (getopt) ... se você quiser que as coisas sejam melhores. Por exemplo:

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

você precisa Littler (pronuncia-se 'pouco r')

Dirk estará daqui a 15 minutos para elaborar;)


11

Como optparsejá foi mencionado algumas vezes nas respostas e fornece um kit abrangente para processamento de linha de comando, aqui está um pequeno exemplo simplificado de como você pode usá-lo, supondo que o arquivo de entrada exista:

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

Dado um arquivo arbitrário blah.txtcom 23 linhas.

Na linha de comando:

Rscript script.R -h saídas

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 saídas [1] "69"

Rscript script.R -n -f 5 blah.txt saídas [1] "115"


7

No bash, você pode construir uma linha de comando como a seguinte:

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

Você pode ver que a variável $zé substituída pelo bash shell com "10" e esse valor é captado commandArgse alimentado args[2], e o comando range x=1:10executado por R com sucesso, etc.


4

FYI: existe uma função args (), que recupera os argumentos das funções R, que não deve ser confundida com um vetor de argumentos chamado args


1
Este certamente não é o caso. Somente funções podem mascarar funções. Criar uma variável com o mesmo nome que uma função não oculta a função. Consulte esta pergunta e respostas: stackoverflow.com/q/6135868/602276
Andrie

É verdade que não mascara. Em geral, tento evitar nomear funções e variáveis ​​com nomes que já existem na R.
Tim


1

Acabei de montar uma boa estrutura de dados e uma cadeia de processamento para gerar esse comportamento de comutação, sem necessidade de bibliotecas. Tenho certeza de que ele já foi implementado várias vezes e me deparei com esse tópico procurando exemplos - pensei em entrar.

Nem sequer precisei de sinalizadores (o único sinalizador aqui é um modo de depuração, criando uma variável que eu verifico como condição para iniciar uma função a jusante if (!exists(debug.mode)) {...} else {print(variables)}). As lapplyinstruções de verificação do sinalizador abaixo produzem o mesmo:

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

onde argsé a variável lida nos argumentos da linha de comando (um vetor de caractere, equivalente a c('--debug','--help')quando você os fornece, por exemplo)

É reutilizável para qualquer outro sinalizador e você evita toda a repetição, sem bibliotecas e sem dependências:

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

Observe que flag.detailsaqui os comandos são armazenados como seqüências de caracteres e avaliados com eval(parse(text = '...')). O Optparse é obviamente desejável para qualquer script sério, mas o código de funcionalidade mínima também é bom às vezes.

Saída de amostra:

$ Rscript check_mail.Rscript --help
--debug Imprime variáveis ​​em vez de executar a função XYZ ...

-h --help Exibir definições de sinalizador
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.