Passando argumentos de linha de comando para R CMD BATCH

102

Tenho usado R CMD BATCH my_script.Rde um terminal para executar um Rscript. Agora estou no ponto em que gostaria de passar um argumento para o comando, mas estou tendo alguns problemas para fazê-lo funcionar. Se eu fizer isso, R CMD BATCH my_script.R blablaele blablase tornará o arquivo de saída, em vez de ser interpretado como um argumento disponível para o script R sendo executado.

Eu tentei o Rscript my_script.R blablaque parece passar blablacorretamente como um argumento, mas não consigo o my_script.Routarquivo de saída que recebo com R CMD BATCH(quero o .Routarquivo). Embora eu pudesse redirecionar a saída de uma chamada para Rscriptpara um nome de arquivo de minha escolha, eu não obteria os comandos de entrada R incluídos no arquivo da maneira que R CMD BATCHacontece no .Routarquivo.

Portanto, idealmente, estou procurando uma maneira de passar argumentos para um script R que está sendo executado por meio do R CMD BATCHmétodo, embora ficaria feliz com uma abordagem usando Rscriptse houver uma maneira de fazê-lo produzir um .Routarquivo comparável .

Bryce Thomas
fonte

Respostas:

114

Minha impressão é que R CMD BATCHé um pouco uma relíquia. Em qualquer caso, o Rscriptexecutável mais recente (disponível em todas as plataformas), junto com commandArgs()torna o processamento de argumentos de linha de comando muito fácil.

Como exemplo, aqui está um pequeno script - chame-o de "myScript.R":

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

E aqui está a aparência de invocá-lo na linha de comando

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

Editar:

Não que eu recomende, mas ... usando uma combinação de source()e sink(), você pode obter Rscriptum .Routarquivo como o produzido por R CMD BATCH. Uma maneira seria criar um pequeno script R - chame -o RscriptEcho.R - que você chama diretamente com Rscript. Pode ser assim:

## 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 executar seu script real, você faria:

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

que será executado myScript.Rcom os argumentos fornecidos e transferirá a entrada, a saída e as mensagens intercaladas para um nome único .Rout.

Edit2:
Você pode executar Rscript detalhadamente e colocar a saída detalhada em um arquivo.

Rscript --verbose myScript.R 5 100 > myScript.Rout
Josh O'Brien
fonte
4
Também tenho a impressão de que R CMD BATCHé uma relíquia. O que eu gosto nele é que ele produz um .Routarquivo que inclui não apenas a saída do script, mas também intercala os comandos / comentários de entrada do .Rarquivo de script que produziu essa saída.
Bryce Thomas
1
Eu te escuto. Esse foi (eu acho que ainda é!) Um aspecto legal de R CMD BATCH.
Josh O'Brien
5
mas acho que você pode fazer melhor do que R CMD BATCHcom knitr, por exemplo Rscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(você pode substituir stitchpor stitch_rhtmlou stitch_rmde precisa instalar knitrdo Github, pois acabei de encontrar um bug em stitch...)
Yihui Xie
7
Só para adicionar meu 0,02, também é fácil usar o redirecionamento do terminal. Um exemplo é Rscript myfile.R > path/to/mylog.Route em vez de ser impresso em stdout (a tela), a saída do arquivo é salva em seu .Routarquivo.
James Pringle
4
Para adicionar ao @JamesPringle, geralmente quero que minha saída seja impressa em uma tela (para monitorar em tempo real) e em um arquivo (para olhar mais tarde). SimRscript myfile.R | tee mylog.Rout
Heisenberg
26

Depois de tentar as opções descritas aqui, encontrei este post do Forester no r-bloggers. Acho que é uma opção limpa a se considerar.

Eu coloquei seu código aqui:

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

Em test.out

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

Graças a Forester !

Alex A.
fonte
Importante notar, se os argumentos forem do tipo caractere, não há necessidade de usar aspas simples / duplas. Ex: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d 01 de
Conforme mencionado na postagem de Forester, --argsé a chave. Também funciona com R --no-save --no-restore --args a=1 < test.ReR --no-save --no-restore < test.R --args a=1
Dave
Existe uma maneira de passar argumentos da linha de comando para o --args? Então, digamos que queremos fazer um loop for na linha de comando e enviá-lo na linha --args.
user2809432
9

Em seu script R, chamado test.R:

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

Na linha de comando, execute:

R CMD BATCH -4 test.R

Seu arquivo de saída, test.Rout, mostrará que o argumento 4foi passado com sucesso para 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
fonte
8

Você precisa colocar argumentos antes my_script.Re usar -nos argumentos, por exemplo

R CMD BATCH -blabla my_script.R

commandArgs()receberá -blablacomo string de caracteres neste caso. Consulte a ajuda para obter detalhes:

$ 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
fonte
2
Eu aviso se eu fazê-lo desta forma e no uso de script args <- commandArgs(FALSE)e, em seguida, imprimir args, eu acabar com todos os argumentos, incluindo os que não são minhas, como --restore, --save, etc. Se eu usar commandArgs(TRUE)fico sem argumentos em tudo. Existe uma maneira de obter apenas meus próprios argumentos adicionais? --argsparece promissor, mas não consegui fazer funcionar ...
Bryce Thomas
Você tem que contar os argumentos do final (por exemplo, tamanho 2, tamanho 1, tamanho) - o seu sempre estará no final.
ynka
4

Acrescento uma resposta porque acho que uma solução de uma linha é sempre boa! No topo do seu myRscript.Rarquivo, adicione a seguinte linha:

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

Em seguida, envie seu script com algo como:

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

Por exemplo:

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

Então:

> ls()
[1] "N"    "l"    "name"
ClementWalter
fonte
0

Esta é outra maneira de processar argumentos de linha de comando, usando R CMD BATCH. Minha abordagem, que se baseia em uma resposta anterior aqui , permite especificar argumentos na linha de comando e, em seu script R, fornecer alguns ou todos os valores padrão.

Aqui está um arquivo R, que chamo de 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)

Na linha de comando, se eu digitar

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

então dentro de R teremos a= 2e b= c(2,5,6). Mas eu poderia, digamos, omitir be acrescentar outro argumento c:

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

Então, em R, teremos a= 2, b= c(1,1,1)(o padrão) e c= "hello".

Finalmente, por conveniência, podemos envolver o código R em uma função, desde que sejamos cuidadosos com o 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)))
Dagremu
fonte