Làm cách nào tôi có thể đọc các tham số dòng lệnh từ tập lệnh R?


281

Tôi đã có một tập lệnh R mà tôi muốn có thể cung cấp một số tham số dòng lệnh (thay vì các giá trị tham số mã cứng trong chính mã). Kịch bản chạy trên Windows.

Tôi không thể tìm thấy thông tin về cách đọc các tham số được cung cấp trên dòng lệnh vào tập lệnh R của tôi. Tôi sẽ ngạc nhiên nếu không thể thực hiện được, vì vậy có lẽ tôi chỉ không sử dụng các từ khóa tốt nhất trong tìm kiếm Google của mình ...

Bất kỳ con trỏ hoặc khuyến nghị?


bạn cần đặt vị trí thực thi

Câu trả lời:


209

Câu trả lời của Dirk ở đây là mọi thứ bạn cần. Đây là một ví dụ tái sản xuất tối thiểu.

Tôi đã tạo hai tệp: exmpl.batexmpl.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

    Ngoài ra, sử dụng 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)

Lưu cả hai tập tin trong cùng một thư mục và bắt đầu exmpl.bat. Trong kết quả, bạn sẽ nhận được:

  • example.png với một số cốt truyện
  • exmpl.batch với tất cả những gì đã được thực hiện

Bạn cũng có thể thêm một biến môi trường %R_Script%:

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

và sử dụng nó trong tập lệnh bó của bạn như %R_Script% <filename.r> <arguments>

Sự khác biệt giữa RScriptRterm:

  • Rscript có cú pháp đơn giản hơn
  • Rscripttự động chọn kiến ​​trúc trên x64 (xem R Cài đặt và quản trị, 2.6 Kiến trúc phụ để biết chi tiết)
  • Rscriptcần options(echo=TRUE)trong tệp .R nếu bạn muốn ghi các lệnh vào tệp đầu ra

127

Một vài điểm:

  1. Các tham số dòng lệnh có thể truy cập thông qua commandArgs(), vì vậy hãy xem help(commandArgs)để biết tổng quan.

  2. Bạn có thể sử dụng Rscript.exetrên tất cả các nền tảng, bao gồm cả Windows. Nó sẽ hỗ trợ commandArgs(). littler có thể được chuyển sang Windows nhưng hiện chỉ có trên OS X và Linux.

  3. Có hai gói bổ trợ trên CRAN - getoptoptparse - cả hai đều được viết để phân tích cú pháp dòng lệnh.

Chỉnh sửa vào tháng 11 năm 2015: Các lựa chọn thay thế mới đã xuất hiện và tôi hết lòng giới thiệu docopt .


2
và có argparse
gkcn

92

Thêm phần này vào đầu tập lệnh của bạn:

args<-commandArgs(TRUE)

Sau đó, bạn có thể tham khảo các đối số được thông qua args[1], args[2]v.v.

Sau đó chạy

Rscript myscript.R arg1 arg2 arg3

Nếu đối số của bạn là các chuỗi có khoảng trắng trong đó, hãy đặt trong dấu ngoặc kép.


7
Điều này chỉ hoạt động khi tôi sử dụng args <-commandArss (TRUE) (lưu ý chữ hoa A).
Andy West

bạn có cần - mở rộng trước arg1 không?
philcolbourn

@philcolbourn Không
Chris_Rands

15

Hãy thử thư viện (getopt) ... nếu bạn muốn mọi thứ đẹp hơn. Ví dụ:

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

11

bạn cần littler (phát âm là 'little r')

Dirk sẽ có trong khoảng 15 phút để xây dựng;)


11

optparseđã được đề cập một vài lần trong các câu trả lời và nó cung cấp một bộ công cụ toàn diện để xử lý dòng lệnh, đây là một ví dụ đơn giản ngắn về cách bạn có thể sử dụng nó, giả sử tệp đầu vào tồn tại:

kịch bản.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))
}

Cho một tập tin tùy ý blah.txtvới 23 dòng.

Trên dòng lệnh:

Rscript script.R -h đầu ra

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 đầu ra [1] "69"

Rscript script.R -n -f 5 blah.txt đầu ra [1] "115"


7

Trong bash, bạn có thể xây dựng một dòng lệnh như sau:

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

Bạn có thể thấy rằng biến $zđược thay thế bằng bash shell bằng "10" và giá trị này được chọn commandArgsvà đưa vào args[2], và lệnh phạm vi được x=1:10thực hiện bởi R thành công, v.v.


4

FYI: có một hàm args (), lấy ra các đối số của hàm R, không bị nhầm lẫn với một vectơ của các đối số có tên là args


1
Điều này gần như chắc chắn không phải là trường hợp. Chỉ các chức năng có thể che dấu các chức năng. Tạo một biến có cùng tên với một hàm không che dấu hàm. Tham khảo câu hỏi và câu trả lời này: stackoverflow.com/q/6135868/602276
Andrie

Đúng, nó không che giấu nó. Nói chung, tôi cố gắng tránh đặt tên hàm và biến bằng tên đã tồn tại trong R.
Tim

1

Nếu bạn cần chỉ định các tùy chọn có cờ, (như -h, --help, --number = 42, v.v.), bạn có thể sử dụng gói R optparse (lấy cảm hứng từ Python): http://cran.r-project.org /web/packages/optparse/vignettes/optparse.pdf .

Ít nhất đây là cách tôi hiểu câu hỏi của bạn, bởi vì tôi đã tìm thấy bài đăng này khi tìm kiếm một tương đương với bash getopt, hoặc perl Getopt, hoặc python argparse và optparse.


1

Tôi chỉ cần kết hợp một cấu trúc dữ liệu đẹp và chuỗi xử lý để tạo hành vi chuyển đổi này, không cần thư viện. Tôi chắc chắn rằng nó sẽ được thực hiện nhiều lần và đã bắt gặp chủ đề này để tìm kiếm các ví dụ - nghĩ rằng tôi đã gắn chip.

Tôi thậm chí không cần cờ đặc biệt (cờ duy nhất ở đây là chế độ gỡ lỗi, tạo một biến mà tôi kiểm tra như một điều kiện để bắt đầu một hàm hạ lưu if (!exists(debug.mode)) {...} else {print(variables)}). Các lapplycâu lệnh kiểm tra cờ dưới đây tạo ra giống như:

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

trong đó argsbiến được đọc từ các đối số dòng lệnh (vectơ ký tự, tương đương với c('--debug','--help')khi bạn cung cấp các ví dụ này)

Nó có thể tái sử dụng cho bất kỳ cờ nào khác và bạn tránh tất cả sự lặp lại và không có thư viện nên không phụ thuộc:

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

Lưu ý rằng ở flag.detailsđây các lệnh được lưu trữ dưới dạng chuỗi, sau đó được ước tính bằng eval(parse(text = '...')). Optparse rõ ràng là mong muốn cho bất kỳ tập lệnh nghiêm trọng nào, nhưng mã chức năng tối thiểu đôi khi cũng tốt.

Đầu ra mẫu:

$ Rscript check_mail.Rscript --help
--debug In các biến thay vì thực thi chức năng XYZ ...

-h - Trợ giúp Hiển thị định nghĩa cờ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.