Przekazywanie argumentów wiersza poleceń do R CMD BATCH

103

Używałem R CMD BATCH my_script.Rz terminala do wykonania Rskryptu. Jestem teraz w punkcie, w którym chciałbym przekazać argument do polecenia, ale mam pewne problemy z jego działaniem. Jeśli robię R CMD BATCH my_script.R blablawtedy blablastaje plik wyjściowy, zamiast interpretować jako argument dostępnych skrypt R jest wykonywany.

Próbowałem, Rscript my_script.R blablaco wydaje się blablapoprawnie przekazywać jako argument, ale potem nie otrzymuję my_script.Routpliku wyjściowego, który otrzymuję R CMD BATCH(chcę .Routplik). Chociaż mógłbym przekierować dane wyjściowe wywołania do Rscriptwybranej przeze mnie nazwy pliku, nie otrzymywałbym poleceń wejściowych R zawartych w pliku w taki R CMD BATCHsam sposób, jak w .Routpliku.

Idealnie więc szukam sposobu na przekazanie argumentów do skryptu języka R wykonywanego za pomocą R CMD BATCHmetody, chociaż byłbym zadowolony z podejścia wykorzystującego, Rscriptjeśli istnieje sposób, aby wygenerować porównywalny .Routplik.

Bryce Thomas
źródło

Odpowiedzi:

115

Mam wrażenie, że R CMD BATCHto trochę relikt. W każdym razie, nowszy Rscriptplik wykonywalny (dostępny na wszystkich platformach), wraz z commandArgs()sprawia, że ​​przetwarzanie argumentów wiersza poleceń jest całkiem łatwe.

Jako przykład, oto mały skrypt - nazwij go "myScript.R" :

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

A oto jak wygląda wywołanie go z linii poleceń

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

Edytować:

Nie to, żebym to polecał, ale ... używając kombinacji source()i sink(), możesz Rscriptstworzyć .Routplik taki jak ten wyprodukowany przez R CMD BATCH. Jednym ze sposobów byłoby stworzenie małego skryptu R - nazwij go RscriptEcho.R - który wywołujesz bezpośrednio za pomocą Rscript. Może to wyglądać tak:

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

Aby wykonać rzeczywisty skrypt, wykonaj następujące czynności:

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

który zostanie wykonany myScript.Rz podanymi argumentami i ujście przeplecione dane wejściowe, wyjściowe i komunikaty do unikatowej nazwy.Rout .

Edycja2:
Możesz uruchomić Rscript w sposób dokładny i umieścić szczegółowe dane wyjściowe w pliku.

Rscript --verbose myScript.R 5 100 > myScript.Rout
Josh O'Brien
źródło
4
Mam też wrażenie, że R CMD BATCHto relikt. Podoba mi się jednak to, że tworzy .Routplik, który zawiera nie tylko dane wyjściowe skryptu, ale także przeplata polecenia / komentarze wejściowe z .Rpliku skryptu, który wygenerował te dane wyjściowe.
Bryce Thomas,
1
Słyszę cię. To był (myślę, że nadal jest!) Miły aspekt R CMD BATCH.
Josh O'Brien,
5
ale myślę, że można to zrobić lepiej niż R CMD BATCHz knitrnp Rscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(można zastąpić stitchz stitch_rhtmllub stitch_rmdi trzeba zainstalować knitrz Github ponieważ właśnie znalazłeś błąd w stitch...)
Yihui Xie
7
Wystarczy dodać moje 0,02, jest też łatwe w użyciu przekierowanie z terminala. Przykładem jest Rscript myfile.R > path/to/mylog.Routi zamiast być wypisywanym na standardowe wyjście (ekran), wynik pliku jest zapisywany w twoim .Routpliku.
James Pringle
4
Aby dodać do @JamesPringle, często chcę, aby mój wynik był drukowany zarówno na ekranie (do monitorowania w czasie rzeczywistym), jak i do pliku (do obejrzenia później). TakRscript myfile.R | tee mylog.Rout
Heisenberg
26

Po wypróbowaniu opisanych tutaj opcji znalazłem ten post od Forester w r-blogerach. Myślę, że to dobra opcja do rozważenia.

Tutaj umieściłem jego kod:

Z wiersza poleceń

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

W test.out

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

Dzięki Forester !

Alex A.
źródło
Należy zauważyć, że jeśli argumenty są typu znakowego, nie ma potrzeby używania pojedynczych / podwójnych cudzysłowów. Np .: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d
Jak wspomniano w poście Forester, --argsjest kluczem. Działa również z R --no-save --no-restore --args a=1 < test.RiR --no-save --no-restore < test.R --args a=1
Dave
Czy istnieje sposób na przekazanie argumentów z wiersza poleceń do --args? Powiedzmy, że chcemy wykonać pętlę for w linii poleceń, a następnie wysłać ją w linii --args.
user2809432
9

Musisz umieścić argumenty przed my_script.Ri użyć -na argumentach, np

R CMD BATCH -blabla my_script.R

commandArgs()otrzyma -blablaw tym przypadku jako ciąg znaków. Zobacz pomoc, aby uzyskać szczegółowe informacje:

$ 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
źródło
2
Zauważyłem, jeśli robię to w ten sposób i w zastosowaniu skryptu args <- commandArgs(FALSE), a następnie wydrukować argumenty, ja skończyć z wszystkich argumentów, w tym te, które nie są moje, jak --restore, --saveitp Jeśli używam commandArgs(TRUE)mam żadnych argumentów w ogóle. Czy jest sposób, aby uzyskać tylko własne dodatkowe argumenty? --argswygląda obiecująco, ale nie udało mi się go uruchomić ...
Bryce Thomas
Musisz liczyć argumenty od końca (np. Rozmiar-2, rozmiar-1, rozmiar) - Twoje zawsze będą na końcu.
ynka
9

W twoim skrypcie R o nazwie test.R:

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

Z wiersza poleceń uruchom:

R CMD BATCH -4 test.R

Twój plik wyjściowy, test.Rout, pokaże, że argument 4został pomyślnie przekazany do 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 
user1563570
źródło
4

Dodaję odpowiedź, ponieważ uważam, że rozwiązanie jednokreskowe jest zawsze dobre! Na górze myRscript.Rpliku dodaj następujący wiersz:

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

Następnie prześlij swój skrypt z czymś takim:

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

Na przykład:

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

Następnie:

> ls()
[1] "N"    "l"    "name"
ClementWalter
źródło
0

Oto inny sposób przetwarzania argumentów wiersza poleceń przy użyciu R CMD BATCH. Moje podejście, które opiera się na wcześniejszej odpowiedzi tutaj , pozwala określić argumenty w wierszu poleceń i, w skrypcie R, podać niektóre lub wszystkie z nich wartości domyślne.

Oto plik R, który nazywam 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)

W wierszu poleceń, jeśli piszę

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

wtedy w R będziemy mieli a= 2i b= c(2,5,6). Ale mógłbym powiedzieć, pominąć bi dodać kolejny argument c:

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

Następnie w R będziemy mieć a= 2, b= c(1,1,1)(domyślnie) i c="hello" .

Wreszcie, dla wygody, możemy zawinąć kod R w funkcję, o ile uważamy na środowisko:

## 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
źródło