Wie kann ich Befehlszeilenparameter aus einem R-Skript lesen?

281

Ich habe ein R-Skript, für das ich mehrere Befehlszeilenparameter bereitstellen möchte (anstelle von Hardcode-Parameterwerten im Code selbst). Das Skript läuft unter Windows.

Ich kann keine Informationen zum Lesen der in der Befehlszeile angegebenen Parameter in mein R-Skript finden. Ich wäre überrascht, wenn dies nicht möglich wäre. Vielleicht verwende ich einfach nicht die besten Keywords in meiner Google-Suche ...

Irgendwelche Hinweise oder Empfehlungen?

monch1962
quelle
Sie müssen den Speicherort der ausführbaren rscript-Datei

Antworten:

209

Dirks Antwort hier ist alles, was Sie brauchen. Hier ist ein minimal reproduzierbares Beispiel.

Ich habe zwei Dateien erstellt: exmpl.batund 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

    Alternativ mit 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)

Speichern Sie beide Dateien im selben Verzeichnis und starten Sie exmpl.bat. Im Ergebnis erhalten Sie:

  • example.png mit etwas Handlung
  • exmpl.batch mit allem was getan wurde

Sie können auch eine Umgebungsvariable hinzufügen %R_Script%:

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

und verwenden Sie es in Ihren Batch-Skripten als %R_Script% <filename.r> <arguments>

Unterschiede zwischen RScriptund Rterm:

  • Rscript hat einfachere Syntax
  • Rscriptwählt automatisch die Architektur unter x64 aus ( Einzelheiten finden Sie unter R Installation und Administration, 2.6 Unterarchitekturen ).
  • Rscriptbenötigt options(echo=TRUE)in der .R-Datei, wenn Sie die Befehle in die Ausgabedatei schreiben möchten
Marek
quelle
127

Ein paar Punkte:

  1. Auf Befehlszeilenparameter kann über commandArgs()zugegriffen werdenhelp(commandArgs) Sie einen Überblick.

  2. Sie können Rscript.exeauf allen Plattformen, einschließlich Windows, verwenden. Es wird unterstützen commandArgs(). kleiner konnte auf Windows portiert werden, lebt aber nur unter OS X und Linux.

  3. Es gibt zwei Add-On-Pakete in CRAN - getopt und optparse - die beide für die Befehlszeilenanalyse geschrieben wurden.

Bearbeiten im November 2015: Neue Alternativen sind erschienen und ich empfehle docopt von ganzem Herzen .

Dirk Eddelbuettel
quelle
2
und es gibt argparse
gkcn
92

Fügen Sie dies oben in Ihr Skript ein:

args<-commandArgs(TRUE)

Dann können Sie auf die Argumente verweisen, die als übergeben wurden args[1] , args[2]usw.

Dann renne

Rscript myscript.R arg1 arg2 arg3

Wenn Ihre Argumente Zeichenfolgen mit Leerzeichen sind, schließen Sie sie in doppelte Anführungszeichen ein.

Hrishi Mittal
quelle
7
Dies funktionierte nur, wenn ich args <-commandArgs (TRUE) verwendete (beachten Sie den Großbuchstaben A).
Andy West
Benötigen Sie --args vor arg1?
Philcolbourn
@philcolbourn No
Chris_Rands
15

Probieren Sie die Bibliothek (getopt) aus ... wenn Sie möchten, dass die Dinge schöner werden. Beispielsweise:

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
quelle
11

du brauchst weniger (ausgesprochen 'kleines r')

Dirk wird in ca. 15 Minuten fertig sein;)

JD Long
quelle
11

Da dies optparsein den Antworten einige Male erwähnt wurde und ein umfassendes Kit für die Befehlszeilenverarbeitung enthält, finden Sie hier ein kurzes, vereinfachtes Beispiel für die Verwendung, sofern die Eingabedatei vorhanden ist:

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

Gegeben eine beliebige Datei blah.txtmit 23 Zeilen.

In der Befehlszeile:

Rscript script.R -h Ausgänge

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 Ausgänge [1] "69"

Rscript script.R -n -f 5 blah.txt Ausgänge [1] "115"

Megatron
quelle
7

In bash können Sie eine Befehlszeile wie folgt erstellen:

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

Sie können sehen, dass die Variable $zdurch die Bash-Shell durch "10" ersetzt wird und dieser Wert von aufgenommen commandArgsund eingegeben args[2]wird und der Bereichsbefehl x=1:10von R erfolgreich ausgeführt wird usw. usw.

TTW
quelle
4

Zu Ihrer Information: Es gibt eine Funktion args (), die die Argumente von R-Funktionen abruft, nicht zu verwechseln mit einem Vektor von Argumenten namens args

Tim
quelle
1
Dies ist mit ziemlicher Sicherheit nicht der Fall. Nur Funktionen können Funktionen maskieren. Durch das Erstellen einer Variablen mit demselben Namen wie eine Funktion wird die Funktion nicht maskiert. Beziehen
Andrie
Es stimmt, es maskiert es nicht. Im Allgemeinen versuche ich zu vermeiden, Funktionen und Variablen mit Namen zu benennen, die bereits in R.
Tim vorhanden sind
1

Wenn Sie Optionen mit Flags angeben müssen (wie -h, --help, --number = 42 usw.), können Sie das R-Paket optparse (inspiriert von Python) verwenden: http://cran.r-project.org /web/packages/optparse/vignettes/optparse.pdf .

Zumindest verstehe ich Ihre Frage so, weil ich diesen Beitrag gefunden habe, als ich nach einem Äquivalent von bash getopt oder perl Getopt oder python argparse und optparse gesucht habe.

TheBinturonGggh
quelle
1

Ich habe gerade eine schöne Datenstruktur und Verarbeitungskette zusammengestellt, um dieses Schaltverhalten zu erzeugen. Es werden keine Bibliotheken benötigt. Ich bin mir sicher, dass es mehrfach implementiert wurde, und bin auf diesen Thread gestoßen, der nach Beispielen gesucht hat - dachte, ich würde mitmachen.

Ich brauchte nicht einmal besonders Flags (das einzige Flag hier ist ein Debug-Modus, der eine Variable erstellt, auf die ich als Bedingung für das Starten einer Downstream-Funktion prüfe if (!exists(debug.mode)) {...} else {print(variables)}). Die folgenden lapplyAnweisungen zur Flag-Prüfung ergeben Folgendes:

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

wo args wird die Variable aus Befehlszeilenargumenten eingelesen (ein Zeichenvektor, der äquivalent zu istc('--debug','--help') wenn Sie diese beispielsweise angeben)?

Es ist für jedes andere Flag wiederverwendbar und Sie vermeiden alle Wiederholungen und keine Bibliotheken, also keine Abhängigkeiten:

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

Beachten Sie, dass flag.detailshier die Befehle als Zeichenfolgen gespeichert und dann mit ausgewertet werdeneval(parse(text = '...')) . Optparse ist natürlich für jedes ernsthafte Skript wünschenswert, aber Code mit minimaler Funktionalität ist manchmal auch gut.

Beispielausgabe:

$ Rscript check_mail.Rscript --help
--debug Gibt Variablen aus, anstatt die Funktion XYZ auszuführen ...

-h --help Flag-Definitionen anzeigen
Louis Maddox
quelle