Passaggio degli argomenti della riga di comando a R CMD BATCH


102

Sto usando R CMD BATCH my_script.Rda un terminale per eseguire uno Rscript. Sono ora al punto in cui vorrei passare un argomento al comando, ma ho alcuni problemi a farlo funzionare. Se faccio R CMD BATCH my_script.R blablaallora blabladiventa il file di output, piuttosto che essere interpretato come un argomento a disposizione viene eseguito lo script R.

Ho provato Rscript my_script.R blablache sembra passare blablacorrettamente come argomento, ma poi non ottengo il my_script.Routfile di output con cui ottengo R CMD BATCH(voglio il .Routfile). Anche se potrei reindirizzare l'output di una chiamata a Rscriptun nome di file di mia scelta, non otterrei i comandi di input R inclusi nel file come R CMD BATCHnel .Routfile.

Quindi, idealmente, sto cercando un modo per passare argomenti a uno script R eseguito tramite il R CMD BATCHmetodo, anche se sarei felice di un approccio che utilizza Rscriptse c'è un modo per far sì che produca un .Routfile comparabile .

Risposte:


114

La mia impressione è che R CMD BATCHsia un po 'relitto. In ogni caso, l' Rscripteseguibile più recente (disponibile su tutte le piattaforme), insieme a commandArgs()rende piuttosto semplice l'elaborazione degli argomenti della riga di comando.

Ad esempio, ecco un piccolo script: chiamalo "myScript.R":

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

Ed ecco come appare l'invocarlo dalla riga di comando

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

Modificare:

Non che lo consiglierei, ma ... usando una combinazione di source()e sink(), potresti arrivare Rscripta produrre un .Routfile come quello prodotto da R CMD BATCH. Un modo potrebbe essere quello di creare un piccolo script R - chiamare esso RscriptEcho.R - che voi chiamate direttamente con rscript. Potrebbe assomigliare a questo:

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

Per eseguire il tuo script effettivo, dovresti quindi fare:

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

che verrà eseguito myScript.Rcon gli argomenti forniti e invierà input, output e messaggi interlacciati a un file .Rout.

Edit2:
è possibile eseguire Rscript in modo verboso e inserire l'output dettagliato in un file.

Rscript --verbose myScript.R 5 100 > myScript.Rout

4
Ho anche l'impressione che R CMD BATCHsia una reliquia. La cosa che mi piace però è che produce un .Routfile che include non solo l'output dello script, ma intercala anche i comandi / commenti di input dal .Rfile di script che ha prodotto quell'output.
Bryce Thomas

1
Ti sento. Quello era (immagino che lo sia ancora!) Un bell'aspetto di R CMD BATCH.
Josh O'Brien

5
ma penso che tu possa fare di meglio che R CMD BATCHcon knitr, ad es. Rscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(puoi sostituire stitchcon stitch_rhtmlo stitch_rmd, e devi installare knitrda Github poiché ho appena trovato un bug in stitch...)
Yihui Xie

7
Solo per aggiungere il mio 0.02, è anche facile usare il reindirizzamento dal terminale. Un esempio è Rscript myfile.R > path/to/mylog.Route invece di essere stampato su stdout (lo schermo), l'output del file viene salvato nel .Routfile.
James Pringle

4
Per aggiungere a @JamesPringle, spesso voglio che il mio output sia stampato sia su uno schermo (da monitorare in tempo reale) che su un file (da guardare in seguito). FaccioRscript myfile.R | tee mylog.Rout
Heisenberg

26

Dopo aver provato le opzioni descritte qui, ho trovato questo post di Forester in r-blogger. Penso che sia un'opzione pulita da considerare.

Ho messo il suo codice qui:

Dalla riga di 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)

In test.out

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

Grazie a Forester !


È importante notare che, se gli argomenti sono di tipo carattere, non è necessario utilizzare virgolette singole / doppie. Ad esempio: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d

Come accennato nel post di Forester, --argsè la chiave. Funziona anche con R --no-save --no-restore --args a=1 < test.ReR --no-save --no-restore < test.R --args a=1
Dave

C'è un modo per passare argomenti dalla riga di comando in --args? Quindi supponiamo di voler eseguire un ciclo for nella riga di comando, quindi inviarlo nella riga --args.
user2809432

9

Nel tuo script R, chiamato test.R:

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

Dalla riga di comando esegui:

R CMD BATCH -4 test.R

Il tuo file di output, test.Rout, mostrerà che l'argomento 4è stato passato con successo 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 

8

È necessario inserire gli argomenti prima my_script.Re utilizzarli -sugli argomenti, ad es

R CMD BATCH -blabla my_script.R

commandArgs()riceverà -blablacome stringa di caratteri in questo caso. Vedere la guida per i dettagli:

$ 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
Ho notato se lo faccio in questo modo e nell'uso di script args <- commandArgs(FALSE)e quindi stampare args, io alla fine con tutti gli argomenti, compresi quelli che non sono miei, come --restore, --saveecc Se uso commandArgs(TRUE)ricevo alcun argomento a tutti. C'è un modo per ottenere solo i miei argomenti aggiuntivi? --argssembra promettente, ma non sono riuscito a farlo funzionare ...
Bryce Thomas

Devi contare gli argomenti dalla fine (ad esempio size-2, size-1, size) - i tuoi saranno sempre alla fine.
ynka

4

Aggiungo una risposta perché penso che una soluzione di una riga sia sempre buona! In cima al myRscript.Rfile, aggiungi la seguente riga:

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

Quindi invia il tuo script con qualcosa del tipo:

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

Per esempio:

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

Poi:

> ls()
[1] "N"    "l"    "name"

0

Ecco un altro modo per elaborare gli argomenti della riga di comando, utilizzando R CMD BATCH. Il mio approccio, che si basa su una risposta precedente qui , ti consente di specificare gli argomenti sulla riga di comando e, nello script R, di fornire alcuni o tutti i valori predefiniti.

Ecco un file R, che chiamo 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)

Alla riga di comando, se digito

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

allora all'interno di R avremo a= 2e b= c(2,5,6). Ma potrei, dire, omettere be aggiungere un altro argomento c:

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

Quindi in R avremo a= 2, b= c(1,1,1)(il valore predefinito) e c= "hello".

Infine, per comodità possiamo racchiudere il codice R in una funzione, purché stiamo attenti all'ambiente:

## 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)))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.