Bagaimana saya bisa membaca parameter baris perintah dari skrip R?

281

Saya punya skrip R yang ingin saya berikan beberapa parameter baris perintah (daripada nilai parameter hardcode dalam kode itu sendiri). Script berjalan pada Windows.

Saya tidak dapat menemukan info tentang cara membaca parameter yang disediakan pada command-line ke dalam skrip R. Saya akan terkejut jika itu tidak dapat dilakukan, jadi mungkin saya tidak menggunakan kata kunci terbaik di pencarian Google saya ...

Adakah petunjuk atau rekomendasi?

monch1962
sumber
Anda perlu mengatur lokasi rscript dapat dieksekusi

Jawaban:

209

Jawaban Dirk di sini adalah semua yang Anda butuhkan. Berikut adalah contoh minimal yang dapat direproduksi.

Saya membuat dua file: exmpl.batdan 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

    Atau, gunakan 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)

Simpan kedua file di direktori yang sama dan mulai exmpl.bat. Dalam hasilnya Anda akan mendapatkan:

  • example.png dengan beberapa plot
  • exmpl.batch dengan semua yang dilakukan

Anda juga bisa menambahkan variabel lingkungan %R_Script%:

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

dan menggunakannya dalam skrip batch Anda sebagai %R_Script% <filename.r> <arguments>

Perbedaan antara RScriptdan Rterm:

  • Rscript memiliki sintaksis yang lebih sederhana
  • Rscriptsecara otomatis memilih arsitektur pada x64 (lihat R Instalasi dan Administrasi, 2.6 Sub-arsitektur untuk perincian)
  • Rscriptperlu options(echo=TRUE)dalam file .R jika Anda ingin menulis perintah ke file output
Marek
sumber
127

Beberapa poin:

  1. Parameter baris perintah dapat diakses melalui commandArgs(), jadi lihat help(commandArgs)ikhtisar.

  2. Anda dapat menggunakan Rscript.exesemua platform, termasuk Windows. Itu akan mendukung commandArgs(). littler dapat di-porting ke Windows tetapi sekarang hanya hidup di OS X dan Linux

  3. Ada dua paket tambahan pada CRAN - getopt dan optparse - yang keduanya ditulis untuk penguraian baris perintah.

Edit pada Nov 2015: Alternatif baru telah muncul dan saya dengan sepenuh hati merekomendasikan docopt .

Dirk Eddelbuettel
sumber
2
dan ada argparse
gkcn
92

Tambahkan ini ke bagian atas skrip Anda:

args<-commandArgs(TRUE)

Kemudian Anda bisa merujuk ke argumen yang diteruskan sebagai args[1],args[2] dll.

Lalu lari

Rscript myscript.R arg1 arg2 arg3

Jika argumen Anda adalah string dengan spasi di dalamnya, sertakan dalam tanda kutip ganda.

Hrishi Mittal
sumber
7
Ini hanya berfungsi ketika saya menggunakan args <-commandArgs (TRUE) (perhatikan huruf besar A).
Andy West
apakah Anda memerlukan --args sebelum arg1?
philcolbourn
@philcolbourn No
Chris_Rands
15

Coba pustaka (getopt) ... jika Anda ingin sesuatu menjadi lebih baik. Sebagai contoh:

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

Anda membutuhkan littler (dilafalkan 'little r')

Dirk akan selesai sekitar 15 menit untuk menguraikan;)

JD Long
sumber
11

Karena optparsetelah disebutkan beberapa kali dalam jawaban, dan ini memberikan kit yang komprehensif untuk pemrosesan baris perintah, berikut adalah contoh singkat yang disederhanakan tentang bagaimana Anda dapat menggunakannya, dengan asumsi file input ada:

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

Diberikan file sewenang-wenang blah.txtdengan 23 baris.

Di baris perintah:

Rscript script.R -h output

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 output [1] "69"

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

Megatron
sumber
7

Di bash, Anda bisa membuat baris perintah seperti berikut:

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

Anda dapat melihat bahwa variabel $zdiganti oleh bash shell dengan "10" dan nilai ini diambil oleh commandArgsdan dimasukkan ke dalam args[2], dan perintah rentang x=1:10dieksekusi oleh R berhasil, dll.

TTW
sumber
4

FYI: ada fungsi args (), yang mengambil argumen fungsi R, jangan dikacaukan dengan vektor argumen bernama args

Tim
sumber
1
Ini hampir pasti bukan itu masalahnya. Hanya fungsi yang bisa menutupi fungsi. Membuat variabel dengan nama yang sama dengan suatu fungsi tidak menutupi fungsi tersebut. Lihat pertanyaan dan jawaban ini: stackoverflow.com/q/6135868/602276
Andrie
Benar, itu tidak menutupi itu. Secara umum, saya mencoba menghindari fungsi penamaan dan variabel dengan nama yang sudah ada di R.
Tim
1

Jika Anda perlu menentukan opsi dengan flag, (seperti -h, --help, --number = 42, dll) Anda dapat menggunakan paket R optparse (terinspirasi dari Python): http://cran.r-project.org /web/packages/optparse/vignettes/optparse.pdf .

Setidaknya begini bagaimana saya memahami pertanyaan Anda, karena saya menemukan posting ini ketika mencari yang setara dengan bash getopt, atau perl Getopt, atau python argparse dan optparse.

TheBinturonGggh
sumber
1

Saya hanya mengumpulkan struktur data yang bagus dan rantai pemrosesan untuk menghasilkan perilaku switching ini, tidak perlu perpustakaan. Saya yakin itu akan diimplementasikan berkali-kali, dan menemukan utas ini mencari contoh - pikir saya akan ikut campur.

Saya bahkan tidak terlalu membutuhkan flag (satu-satunya flag di sini adalah mode debug, membuat variabel yang saya periksa sebagai syarat untuk memulai fungsi hilir if (!exists(debug.mode)) {...} else {print(variables)}). lapplyPernyataan pemeriksaan bendera di bawah ini menghasilkan yang sama dengan:

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

di mana argsvariabel dibaca dari argumen baris perintah (vektor karakter, setara denganc('--debug','--help') ketika Anda memasok ini misalnya)

Ini dapat digunakan kembali untuk bendera lain dan Anda menghindari semua pengulangan, dan tidak ada perpustakaan sehingga tidak ada ketergantungan:

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

Perhatikan bahwa di flag.detailssini perintah disimpan sebagai string, kemudian dievaluasi dengan eval(parse(text = '...')). Optparse jelas diinginkan untuk skrip serius, tetapi kode fungsionalitas minimal juga baik.

Output sampel:

$ Rscript check_mail.Rscript --help
--debug Cetak variabel daripada menjalankan fungsi XYZ ...

-h --help Menampilkan definisi flag
Louis Maddox
sumber