¿Cómo puedo leer los parámetros de la línea de comandos de un script R?


281

Tengo un script R para el que me gustaría poder proporcionar varios parámetros de línea de comandos (en lugar de valores de parámetros de código rígido en el propio código). El script se ejecuta en Windows.

No puedo encontrar información sobre cómo leer los parámetros suministrados en la línea de comandos en mi script R. Me sorprendería si no se puede hacer, así que tal vez simplemente no estoy usando las mejores palabras clave en mi búsqueda de Google ...

¿Alguna sugerencia o recomendación?


necesita establecer la ubicación del ejecutable

Respuestas:


209

La respuesta de Dirk aquí es todo lo que necesitas. Aquí hay un ejemplo mínimo reproducible.

Hice dos archivos: exmpl.baty 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

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

Guarde ambos archivos en el mismo directorio y comience exmpl.bat. En el resultado obtendrás:

  • example.png con alguna trama
  • exmpl.batch con todo lo que se hizo

También puede agregar una variable de entorno %R_Script%:

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

y úsalo en tus scripts por lotes como %R_Script% <filename.r> <arguments>

Diferencias entre RScripty Rterm:

  • Rscript tiene una sintaxis más simple
  • Rscriptelige automáticamente la arquitectura en x64 (consulte R Instalación y administración, 2.6 Subarquitecturas para más detalles)
  • Rscriptnecesita options(echo=TRUE)en el archivo .R si desea escribir los comandos en el archivo de salida

127

Algunos puntos:

  1. Se puede acceder a los parámetros de la línea de comandos a través de commandArgs(), así que vea help(commandArgs)para una descripción general.

  2. Puede usarlo Rscript.exeen todas las plataformas, incluido Windows. Lo apoyará commandArgs(). littler podría ser portado a Windows, pero ahora solo vive en OS X y Linux.

  3. Hay dos paquetes de complementos en CRAN - getopt y optparse - que fueron escritos para el análisis de la línea de comandos.

Editar en noviembre de 2015: han aparecido nuevas alternativas y recomiendo docopt de todo corazón .


2
y hay argparse
gkcn

92

Agregue esto a la parte superior de su script:

args<-commandArgs(TRUE)

Luego puede referirse a los argumentos pasados ​​como args[1], args[2]etc.

Entonces corre

Rscript myscript.R arg1 arg2 arg3

Si sus argumentos son cadenas con espacios en ellos, encierre entre comillas dobles.


77
Esto solo funcionó cuando usé args <-commandArgs (TRUE) (tenga en cuenta la A mayúscula).
Andy West

necesitas --args antes de arg1?
philcolbourn

@philcolbourn No
Chris_Rands

15

Prueba library (getopt) ... si quieres que las cosas sean más agradables. Por ejemplo:

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

necesitas littler (pronunciado 'little r')

Dirk llegará en unos 15 minutos para elaborar;)


11

Como optparsese ha mencionado un par de veces en las respuestas y proporciona un kit completo para el procesamiento de la línea de comandos, aquí hay un breve ejemplo simplificado de cómo puede usarlo, suponiendo que exista el archivo de entrada:

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 un archivo arbitrario blah.txtcon 23 líneas.

En la línea de comando:

Rscript script.R -h salidas

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 salidas [1] "69"

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


7

En bash, puede construir una línea de comando como la siguiente:

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

Puede ver que la variable $zse sustituye por bash shell con "10" y este valor es recogido commandArgsy alimentado args[2], y el comando de rango x=1:10ejecutado con éxito por R, etc.


4

FYI: hay una función args (), que recupera los argumentos de las funciones R, que no debe confundirse con un vector de argumentos llamado args


1
Es casi seguro que este no es el caso. Solo las funciones pueden enmascarar funciones. Crear una variable con el mismo nombre que una función no oculta la función. Consulte esta pregunta y sus respuestas: stackoverflow.com/q/6135868/602276
Andrie el

Es cierto, no lo enmascara. Solo en general, trato de evitar nombrar funciones y variables con nombres que ya existen en R.
Tim


1

Acabo de armar una buena estructura de datos y una cadena de procesamiento para generar este comportamiento de conmutación, no se necesitan bibliotecas. Estoy seguro de que se habrá implementado varias veces, y encontré este hilo en busca de ejemplos, pensé que lo incluiría.

Ni siquiera necesitaba indicadores en particular (el único indicador aquí es un modo de depuración, creando una variable que verifico como condición para iniciar una función descendente if (!exists(debug.mode)) {...} else {print(variables)}). Las lapplysiguientes declaraciones de comprobación de indicador producen lo mismo que:

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

donde argsestá la variable leída de los argumentos de la línea de comandos (un vector de caracteres, equivalente ac('--debug','--help') cuando los proporciona, por ejemplo)?

Es reutilizable para cualquier otro indicador y evita toda la repetición, y no hay bibliotecas, por lo que no hay dependencias:

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

Tenga en cuenta que flag.detailsaquí los comandos se almacenan como cadenas, luego se evalúan con eval(parse(text = '...')). Optparse es obviamente deseable para cualquier script serio, pero el código de funcionalidad mínima también es bueno a veces.

Salida de muestra:

$ Rscript check_mail.Rscript --help
--debug Imprime variables en lugar de ejecutar la función XYZ ...

-h --help Mostrar definiciones de banderas
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.