Passer des arguments de ligne de commande à R CMD BATCH

102

J'utilise R CMD BATCH my_script.Rdepuis un terminal pour exécuter un Rscript. J'en suis maintenant au point où je voudrais passer un argument à la commande, mais j'ai des problèmes pour le faire fonctionner. Si je le fais R CMD BATCH my_script.R blablaalors blabladevient le fichier de sortie, plutôt que d'être interprété comme un argument disponible pour le script R en cours d'exécution.

J'ai essayé Rscript my_script.R blablace qui semble passer blablacorrectement en argument, mais je n'obtiens pas le my_script.Routfichier de sortie avec lequel j'obtiens R CMD BATCH(je veux le .Routfichier). Bien que je puisse rediriger la sortie d'un appel vers Rscriptun nom de fichier de mon choix, je n'obtiendrais pas les commandes d'entrée R incluses dans le fichier de la même manière R CMD BATCHque dans le .Routfichier.

Donc, idéalement, je cherche un moyen de passer des arguments à un script R exécuté via la R CMD BATCHméthode, mais je serais heureux avec une approche utilisant Rscripts'il existe un moyen de le faire produire un .Routfichier comparable .

Bryce Thomas
la source

Réponses:

114

J'ai l'impression que R CMD BATCHc'est un peu une relique. Dans tous les cas, l' Rscriptexécutable le plus récent (disponible sur toutes les plates-formes), ainsi que commandArgs()facilite le traitement des arguments de ligne de commande.

À titre d'exemple, voici un petit script - appelez-le "myScript.R":

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

Et voici à quoi ressemble son invocation depuis la ligne de commande

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

Éditer:

Non pas que je le recommande, mais ... en utilisant une combinaison de source()et sink(), vous pourriez obtenir Rscriptun .Routfichier comme celui produit par R CMD BATCH. Une façon serait de créer un petit script R - appelez- le RscriptEcho.R - que vous appelez directement avec Rscript. Cela pourrait ressembler à ceci:

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

Pour exécuter votre script réel, vous feriez alors:

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

qui s'exécutera myScript.Ravec les arguments fournis et transmettra l'entrée, la sortie et les messages entrelacés à un nom unique .Rout.

Edit2:
Vous pouvez exécuter Rscript de manière verbeuse et placer la sortie détaillée dans un fichier.

Rscript --verbose myScript.R 5 100 > myScript.Rout
Josh O'Brien
la source
4
J'ai aussi l'impression que R CMD BATCHc'est une relique. Ce que j'aime, c'est qu'il produit un .Routfichier qui comprend non seulement la sortie du script, mais également entrelace les commandes d'entrée / commentaires du .Rfichier de script qui a produit cette sortie.
Bryce Thomas
1
Je t'entends. C'était (je suppose que c'est toujours!) Un bel aspect de R CMD BATCH.
Josh O'Brien
5
mais je pense que vous pouvez faire mieux R CMD BATCHqu'avec knitr, par exemple Rscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(vous pouvez remplacer stitchpar stitch_rhtmlou stitch_rmd, et vous devez installer à knitrpartir de Github puisque je viens de trouver un bogue dans stitch...)
Yihui Xie
7
Juste pour ajouter mon 0.02, il est également facile d'utiliser la redirection depuis le terminal. Un exemple est Rscript myfile.R > path/to/mylog.Routet au lieu d'être imprimé sur stdout (l'écran), la sortie du fichier est enregistrée dans votre .Routfichier.
James Pringle
4
Pour ajouter à @JamesPringle, je souhaite souvent que ma sortie soit à la fois imprimée sur un écran (pour surveiller en temps réel) et dans un fichier (à regarder plus tard). I doRscript myfile.R | tee mylog.Rout
Heisenberg
26

Après avoir essayé les options décrites ici, j'ai trouvé cet article de Forester dans r-bloggers. Je pense que c'est une option propre à considérer.

J'ai mis son code ici:

Depuis la ligne de commande

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

Dans test.out

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

Merci à Forester !

Alex A.
la source
Important à noter, si les arguments sont de type caractère, pas besoin d'utiliser des guillemets simples / doubles. Par exemple: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d
Comme mentionné dans l'article de Forester, --argsc'est la clé. Il fonctionne également avec R --no-save --no-restore --args a=1 < test.RetR --no-save --no-restore < test.R --args a=1
Dave
Existe-t-il un moyen de passer des arguments de la ligne de commande dans le --args? Disons que nous voulons faire une boucle for dans la ligne de commande, puis l'envoyer dans la ligne --args.
user2809432
9

Dans votre script R, appelé test.R:

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

À partir de la ligne de commande, exécutez:

R CMD BATCH -4 test.R

Votre fichier de sortie, test.Rout, montrera que l'argument 4a été passé avec succès à 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 
utilisateur1563570
la source
8

Vous devez mettre des arguments avant my_script.Ret utiliser -sur les arguments, par exemple

R CMD BATCH -blabla my_script.R

commandArgs()recevra -blablasous forme de chaîne de caractères dans ce cas. Consultez l'aide pour plus de détails:

$ 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
la source
2
Je remarque si je le fais de cette façon et dans l'utilisation du script args <- commandArgs(FALSE), puis imprimer args, je me retrouve avec tous les arguments, y compris ceux qui ne sont pas à moi, comme --restore, --saveetc. Si je commandArgs(TRUE)je reçois aucun argument. Existe-t-il un moyen d'obtenir uniquement mes propres arguments supplémentaires? --argssemble prometteur, mais je n'ai pas été en mesure de le faire fonctionner ...
Bryce Thomas
Vous devez compter les arguments à partir de la fin (par exemple, taille-2, taille-1, taille) - le vôtre sera toujours à la fin.
ynka
4

J'ajoute une réponse car je pense qu'une solution en une ligne est toujours bonne! Au sommet de votre myRscript.Rfichier, ajoutez la ligne suivante:

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

Ensuite, soumettez votre script avec quelque chose comme:

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

Par exemple:

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

Ensuite:

> ls()
[1] "N"    "l"    "name"
ClémentWalter
la source
0

Voici une autre façon de traiter les arguments de ligne de commande, en utilisant R CMD BATCH. Mon approche, qui s'appuie sur une réponse précédente ici , vous permet de spécifier des arguments en ligne de commande et, dans votre script R, de leur donner certaines ou toutes les valeurs par défaut.

Voici un fichier R, que je nomme 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)

Sur la ligne de commande, si je tape

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

alors dans R nous aurons a= 2et b= c(2,5,6). Mais je pourrais dire, omettre bet ajouter un autre argument c:

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

Ensuite, dans R, nous aurons a= 2, b= c(1,1,1)(la valeur par défaut) et c= "hello".

Enfin, pour plus de commodité, nous pouvons envelopper le code R dans une fonction, tant que nous faisons attention à l'environnement:

## 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
la source