Comment lire les paramètres de ligne de commande d'un script R?

281

J'ai un script R pour lequel j'aimerais pouvoir fournir plusieurs paramètres de ligne de commande (plutôt que des valeurs de paramètres de code dur dans le code lui-même). Le script s'exécute sur Windows.

Je ne trouve pas d'informations sur la façon de lire les paramètres fournis sur la ligne de commande dans mon script R. Je serais surpris si cela ne pouvait pas être fait, alors peut-être que je n'utilise tout simplement pas les meilleurs mots clés dans ma recherche Google ...

Des conseils ou des recommandations?

monch1962
la source
vous devez définir l'emplacement de l'exécutable

Réponses:

209

La réponse de Dirk ici est tout ce dont vous avez besoin. Voici un exemple reproductible minimal.

J'ai fait deux fichiers: exmpl.batet exmpl.R.

  • exmpl.bat:

    set R_Script="C:\Program Files\R-3.0.2\bin\RScript.exe"
    %R_Script% exmpl.R 2010-01-28 example 100 > exmpl.batch 2>&1
    

    Alternativement, en utilisant Rterm.exe:

    set R_TERM="C:\Program Files\R-3.0.2\bin\i386\Rterm.exe"
    %R_TERM% --no-restore --no-save --args 2010-01-28 example 100 < exmpl.R > exmpl.batch 2>&1
    
  • exmpl.R:

    options(echo=TRUE) # if you want see commands in output file
    args <- commandArgs(trailingOnly = TRUE)
    print(args)
    # trailingOnly=TRUE means that only your arguments are returned, check:
    # print(commandArgs(trailingOnly=FALSE))
    
    start_date <- as.Date(args[1])
    name <- args[2]
    n <- as.integer(args[3])
    rm(args)
    
    # Some computations:
    x <- rnorm(n)
    png(paste(name,".png",sep=""))
    plot(start_date+(1L:n), x)
    dev.off()
    
    summary(x)
    

Enregistrez les deux fichiers dans le même répertoire et démarrez exmpl.bat. Dans le résultat, vous obtiendrez:

  • example.png avec un complot
  • exmpl.batch avec tout ce qui a été fait

Vous pouvez également ajouter une variable d'environnement %R_Script%:

"C:\Program Files\R-3.0.2\bin\RScript.exe"

et l'utiliser dans vos scripts batch comme %R_Script% <filename.r> <arguments>

Différences entre RScriptet Rterm:

Marek
la source
127

Quelques points:

  1. Les paramètres de ligne de commande sont accessibles via commandArgs(), voir donc help(commandArgs)pour un aperçu.

  2. Vous pouvez utiliser Rscript.exesur toutes les plateformes, y compris Windows. Il soutiendra commandArgs(). littler pourrait être porté sur Windows mais ne vit actuellement que sur OS X et Linux.

  3. Il existe deux modules complémentaires sur CRAN - getopt et optparse - qui ont tous deux été écrits pour l'analyse en ligne de commande.

Edit en novembre 2015: de nouvelles alternatives sont apparues et je recommande sans réserve docopt .

Dirk Eddelbuettel
la source
2
et il y a argparse
gkcn
92

Ajoutez ceci en haut de votre script:

args<-commandArgs(TRUE)

Ensuite, vous pouvez vous référer aux arguments passés comme args[1], args[2]etc.

Exécutez ensuite

Rscript myscript.R arg1 arg2 arg3

Si vos arguments sont des chaînes contenant des espaces, placez-les entre guillemets.

Hrishi Mittal
la source
7
Cela ne fonctionnait que lorsque j'utilisais args <-commandArgs (TRUE) (notez le A majuscule).
Andy West
avez-vous besoin de --args avant arg1?
philcolbourn
@philcolbourn No
Chris_Rands
15

Essayez la bibliothèque (getopt) ... si vous voulez que les choses soient plus belles. Par exemple:

spec <- matrix(c(
        'in'     , 'i', 1, "character", "file from fastq-stats -x (required)",
        'gc'     , 'g', 1, "character", "input gc content file (optional)",
        'out'    , 'o', 1, "character", "output filename (optional)",
        'help'   , 'h', 0, "logical",   "this help"
),ncol=5,byrow=T)

opt = getopt(spec);

if (!is.null(opt$help) || is.null(opt$in)) {
    cat(paste(getopt(spec, usage=T),"\n"));
    q();
}
Erik Aronesty
la source
11

vous avez besoin de plus petit (prononcé «petit r»)

Dirk sera dans environ 15 minutes pour élaborer;)

JD Long
la source
11

Puisqu'il optparsea été mentionné plusieurs fois dans les réponses et qu'il fournit un kit complet pour le traitement en ligne de commande, voici un bref exemple simplifié de la façon dont vous pouvez l'utiliser, en supposant que le fichier d'entrée existe:

script.R:

library(optparse)

option_list <- list(
  make_option(c("-n", "--count_lines"), action="store_true", default=FALSE,
    help="Count the line numbers [default]"),
  make_option(c("-f", "--factor"), type="integer", default=3,
    help="Multiply output by this number [default %default]")
)

parser <- OptionParser(usage="%prog [options] file", option_list=option_list)

args <- parse_args(parser, positional_arguments = 1)
opt <- args$options
file <- args$args

if(opt$count_lines) {
  print(paste(length(readLines(file)) * opt$factor))
}

Étant donné un fichier arbitraire blah.txtde 23 lignes.

Sur la ligne de commande:

Rscript script.R -h les sorties

Usage: script.R [options] file


Options:
        -n, --count_lines
                Count the line numbers [default]

        -f FACTOR, --factor=FACTOR
                Multiply output by this number [default 3]

        -h, --help
                Show this help message and exit

Rscript script.R -n blah.txt les sorties [1] "69"

Rscript script.R -n -f 5 blah.txt les sorties [1] "115"

Megatron
la source
7

En bash, vous pouvez construire une ligne de commande comme celle-ci:

$ z=10
$ echo $z
10
$ Rscript -e "args<-commandArgs(TRUE);x=args[1]:args[2];x;mean(x);sd(x)" 1 $z
 [1]  1  2  3  4  5  6  7  8  9 10
[1] 5.5
[1] 3.027650
$

Vous pouvez voir que la variable $zest remplacée par bash shell avec "10" et cette valeur est récupérée par commandArgset introduite dans args[2], et la commande range x=1:10exécutée par R avec succès, etc.

TTW
la source
4

Pour info: il existe une fonction args (), qui récupère les arguments des fonctions R, à ne pas confondre avec un vecteur d'arguments nommé args

Tim
la source
1
Ce n'est certainement pas le cas. Seules les fonctions peuvent masquer des fonctions. La création d'une variable portant le même nom qu'une fonction ne masque pas la fonction. Reportez-vous à cette question et réponses: stackoverflow.com/q/6135868/602276
Andrie
Certes, cela ne le masque pas. Juste en général, j'essaie d'éviter de nommer des fonctions et des variables avec des noms qui existent déjà dans R.
Tim
1

Si vous devez spécifier des options avec des drapeaux (comme -h, --help, --number = 42, etc.), vous pouvez utiliser le package R optparse (inspiré de Python): http://cran.r-project.org /web/packages/optparse/vignettes/optparse.pdf .

Au moins, c'est ainsi que je comprends votre question, car j'ai trouvé ce message en recherchant un équivalent de bash getopt, ou perl Getopt, ou python argparse et optparse.

TheBinturonGggh
la source
1

Je viens de mettre en place une belle structure de données et une chaîne de traitement pour générer ce comportement de commutation, aucune bibliothèque nécessaire. Je suis sûr qu'il aura été mis en œuvre de nombreuses fois, et je suis tombé sur ce fil à la recherche d'exemples - pensais que j'y participerais.

Je n'avais même pas particulièrement besoin d'indicateurs (le seul indicateur ici est un mode de débogage, créant une variable que je vérifie comme condition de démarrage d'une fonction en aval if (!exists(debug.mode)) {...} else {print(variables)}). Les lapplyinstructions de vérification d'indicateur ci-dessous produisent la même chose que:

if ("--debug" %in% args) debug.mode <- T
if ("-h" %in% args || "--help" %in% args) 

argsest la variable lue dans les arguments de la ligne de commande (un vecteur de caractères, équivalent à c('--debug','--help')lorsque vous les fournissez par exemple)

Il est réutilisable pour tout autre indicateur et vous évitez toutes les répétitions, et pas de bibliothèques donc pas de dépendances:

args <- commandArgs(TRUE)

flag.details <- list(
"debug" = list(
  def = "Print variables rather than executing function XYZ...",
  flag = "--debug",
  output = "debug.mode <- T"),
"help" = list(
  def = "Display flag definitions",
  flag = c("-h","--help"),
  output = "cat(help.prompt)") )

flag.conditions <- lapply(flag.details, function(x) {
  paste0(paste0('"',x$flag,'"'), sep = " %in% args", collapse = " || ")
})
flag.truth.table <- unlist(lapply(flag.conditions, function(x) {
  if (eval(parse(text = x))) {
    return(T)
  } else return(F)
}))

help.prompts <- lapply(names(flag.truth.table), function(x){
# joins 2-space-separatated flags with a tab-space to the flag description
  paste0(c(paste0(flag.details[x][[1]][['flag']], collapse="  "),
  flag.details[x][[1]][['def']]), collapse="\t")
} )

help.prompt <- paste(c(unlist(help.prompts),''),collapse="\n\n")

# The following lines handle the flags, running the corresponding 'output' entry in flag.details for any supplied
flag.output <- unlist(lapply(names(flag.truth.table), function(x){
  if (flag.truth.table[x]) return(flag.details[x][[1]][['output']])
}))
eval(parse(text = flag.output))

Notez flag.detailsqu'ici, les commandes sont stockées sous forme de chaînes, puis évaluées avec eval(parse(text = '...')). Optparse est évidemment souhaitable pour tout script sérieux, mais le code à fonctionnalité minimale est parfois bon aussi.

Exemple de sortie:

$ Rscript check_mail.Rscript --help
--debug Affiche les variables plutôt que d'exécuter la fonction XYZ ...

-h --help Afficher les définitions d'indicateur
Louis Maddox
la source