Pasando argumentos de línea de comando a R CMD BATCH

102

He estado usando R CMD BATCH my_script.Rdesde una terminal para ejecutar un Rscript. Ahora estoy en el punto en el que me gustaría pasar un argumento al comando, pero tengo algunos problemas para que funcione. Si lo hago, R CMD BATCH my_script.R blablase blablaconvierte en el archivo de salida, en lugar de ser interpretado como un argumento disponible para el script R que se está ejecutando.

He intentado Rscript my_script.R blablaque parece pasar blablacorrectamente como argumento, pero luego no obtengo el my_script.Routarchivo de salida con el que obtengo R CMD BATCH(quiero el .Routarchivo). Si bien podría redirigir la salida de una llamada a Rscriptun nombre de archivo de mi elección, no obtendría los comandos de entrada R incluidos en el archivo de la forma R CMD BATCHen que lo hace en el .Routarchivo.

Entonces, idealmente, busco una manera de pasar argumentos a un script R que se está ejecutando a través del R CMD BATCHmétodo, aunque estaría contento con un enfoque que use Rscriptsi hay una manera de hacer que produzca un .Routarchivo comparable .

Bryce Thomas
fuente

Respuestas:

114

Mi impresión es que R CMD BATCHes un poco reliquia. En cualquier caso, el Rscriptejecutable más reciente (disponible en todas las plataformas), junto con, commandArgs()hace que procesar los argumentos de la línea de comandos sea bastante fácil.

Como ejemplo, aquí hay un pequeño script, llámelo "myScript.R":

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

Y así es como se ve invocarlo desde la línea de comando

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

Editar:

No es que lo recomiende, pero ... usando una combinación de source()y sink(), podrías llegar Rscripta producir un .Routarchivo como el producido por R CMD BATCH. Una forma sería crear un pequeño script R - llamar que RscriptEcho.R - lo que se llama directamente con RSCRIPT. Podría verse así:

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

Para ejecutar su secuencia de comandos real, debe hacer:

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

que se ejecutará myScript.Rcon los argumentos proporcionados y enviará entradas, salidas y mensajes intercalados a un archivo .Rout.

Edit2:
puede ejecutar Rscript de forma detallada y colocar la salida detallada en un archivo.

Rscript --verbose myScript.R 5 100 > myScript.Rout
Josh O'Brien
fuente
4
También me da la impresión de que R CMD BATCHes una reliquia. Sin embargo, lo que me gusta de él es que produce un .Routarchivo que incluye no solo la salida del script, sino que también intercala los comandos / comentarios de entrada del .Rarchivo de script que produjo esa salida.
Bryce Thomas
1
Te escucho. Ese fue (¡supongo que todavía lo es!) Un buen aspecto de R CMD BATCH.
Josh O'Brien
5
pero creo que puede hacerlo mejor que R CMD BATCHcon knitr, por ejemplo Rscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(puede reemplazar stitchcon stitch_rhtmlo stitch_rmd, y necesita instalar knitrdesde Github ya que acabo de encontrar un error en stitch...)
Yihui Xie
7
Solo para agregar mi 0.02, también es fácil de usar la redirección desde la terminal. Un ejemplo es Rscript myfile.R > path/to/mylog.Routy en lugar de imprimirse en stdout (la pantalla), la salida del archivo se guarda en su .Routarchivo.
James Pringle
4
Para agregar a @JamesPringle, a menudo quiero que mi salida se imprima en una pantalla (para monitorear en tiempo real) y en un archivo (para ver más tarde). HagoRscript myfile.R | tee mylog.Rout
Heisenberg
26

Después de probar las opciones descritas aquí, encontré esta publicación de Forester en r-bloggers. Creo que es una opción limpia a considerar.

Pongo su código aquí:

Desde la línea de comando

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

En test.out

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

¡Gracias a Forester !

Alex A.
fuente
Es importante tener en cuenta que si los argumentos son de tipo carácter, no es necesario utilizar comillas simples / dobles. Por ejemplo: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d
Como se menciona en la publicación de Forester, --argses la clave. También funciona con R --no-save --no-restore --args a=1 < test.RyR --no-save --no-restore < test.R --args a=1
Dave
¿Hay alguna forma de pasar argumentos de la línea de comando a --args? Entonces, digamos que queremos hacer un bucle for en la línea de comando y luego enviarlo en la línea --args.
user2809432
9

En su script R, llamado test.R:

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

Desde la línea de comando, ejecute:

R CMD BATCH -4 test.R

Su archivo de salida, test.Rout, mostrará que el argumento 4se ha pasado con éxito a 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 
usuario1563570
fuente
8

Debe poner argumentos antes my_script.Ry usarlos -en los argumentos, por ejemplo

R CMD BATCH -blabla my_script.R

commandArgs()recibirá -blablacomo una cadena de caracteres en este caso. Consulte la ayuda para obtener más detalles:

$ 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.
Yihui Xie
fuente
2
Me he dado cuenta, si lo hago de esta manera y en el uso de la escritura args <- commandArgs(FALSE)y luego imprimir args, termino con todos los argumentos, incluidos los que no son míos, como --restore, --save, etc. Si utilizo commandArgs(TRUE)consigo ningún argumento en absoluto. ¿Hay alguna manera de obtener mis propios argumentos adicionales? --argsparece prometedor, pero no he podido hacer que funcione ...
Bryce Thomas
Tienes que contar los argumentos desde el final (por ejemplo, tamaño-2, tamaño-1, tamaño); el tuyo siempre estará al final.
ynka
4

¡Agrego una respuesta porque creo que una solución de una línea siempre es buena! Encima de su myRscript.Rarchivo, agregue la siguiente línea:

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

Luego envíe su script con algo como:

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

Por ejemplo:

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

Luego:

> ls()
[1] "N"    "l"    "name"
ClementeWalter
fuente
0

Aquí hay otra forma de procesar argumentos de línea de comando, usando R CMD BATCH. Mi enfoque, que se basa en una respuesta anterior aquí , le permite especificar argumentos en la línea de comando y, en su secuencia de comandos R, dar algunos o todos los valores predeterminados.

Aquí hay un archivo R, que llamo 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)

En la línea de comando, si escribo

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

luego dentro de R tendremos a= 2y b= c(2,5,6). Pero podría, decir, omitir by agregar otro argumento c:

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

Luego, en R tendremos a= 2, b= c(1,1,1)(el valor predeterminado) y c= "hello".

Finalmente, por conveniencia, podemos envolver el código R en una función, siempre que tengamos cuidado con el entorno:

## 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)))
Dagremu
fuente