Truyền đối số dòng lệnh cho R CMD BATCH


102

Tôi đã sử dụng R CMD BATCH my_script.Rtừ một thiết bị đầu cuối để thực thi một Rtập lệnh. Bây giờ tôi đã đến thời điểm mà tôi muốn chuyển một đối số cho lệnh, nhưng đang gặp một số vấn đề để nó hoạt động. Nếu tôi làm vậy R CMD BATCH my_script.R blablathì nó blablasẽ trở thành tệp đầu ra, thay vì được hiểu là một đối số có sẵn cho tập lệnh R đang được thực thi.

Tôi đã thử Rscript my_script.R blablamà dường như truyền blablađúng như một đối số, nhưng sau đó tôi không nhận được my_script.Routtệp đầu ra mà tôi nhận được R CMD BATCH(tôi muốn .Routtệp). Trong khi tôi có thể chuyển hướng đầu ra của lệnh gọi đến Rscripttên tệp mà tôi chọn, tôi sẽ không nhận được các lệnh đầu vào R có trong tệp theo cách R CMD BATCHthực hiện trong .Routtệp.

Vì vậy, lý tưởng nhất là tôi đang tìm kiếm một cách để truyền các đối số đến một tập lệnh R đang được thực thi thông qua R CMD BATCHphương thức, mặc dù sẽ rất vui với một cách tiếp cận bằng cách sử dụng Rscriptnếu có cách để làm cho nó tạo ra một .Routtệp có thể so sánh được .

Câu trả lời:


114

Ấn tượng của tôi R CMD BATCHlà một chút dựa dẫm. Trong mọi trường hợp, Rscripttệp thực thi mới hơn (có sẵn trên tất cả các nền tảng), cùng vớicommandArgs() việc xử lý các đối số dòng lệnh khá dễ dàng.

Ví dụ, đây là một tập lệnh nhỏ - hãy gọi nó "myScript.R":

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

Và đây là những gì gọi nó từ dòng lệnh trông như thế nào

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

Biên tập:

Không phải tôi muốn giới thiệu nó, nhưng ... sử dụng kết hợp source()sink(), bạn có thể Rscripttạo ra một .Routtệp giống như được tạo bởi R CMD BATCH. Một cách là tạo một tập lệnh R nhỏ - hãy gọi RscriptEcho.R - mà bạn gọi trực tiếp bằng Rscript. Nó có thể trông như thế này:

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

Để thực thi tập lệnh thực của bạn, sau đó bạn sẽ làm:

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

sẽ thực thi myScript.Rvới các đối số được cung cấp và đưa đầu vào, đầu ra và thông báo xen kẽ vào một tên duy nhất .Rout.

Edit2:
Bạn có thể chạy Rscript một cách chi tiết và đặt đầu ra dài dòng vào một tệp.

Rscript --verbose myScript.R 5 100 > myScript.Rout

4
Tôi cũng có ấn tượng R CMD BATCHlà một di tích. Tuy nhiên, điều tôi thích ở nó là nó tạo ra một .Routtệp không chỉ bao gồm đầu ra tập lệnh mà còn xen kẽ các lệnh / nhận xét đầu vào từ .Rtệp kịch bản tạo ra đầu ra đó.
Bryce Thomas

1
Tôi nghe bạn. Đó là (tôi đoán vẫn là!) Một khía cạnh tốt đẹp của R CMD BATCH.
Josh O'Brien

5
nhưng tôi nghĩ bạn có thể làm tốt hơn R CMD BATCHvới knitr, ví dụ: Rscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(bạn có thể thay thế stitchbằng stitch_rhtmlhoặc stitch_rmdvà bạn cần cài đặt knitrtừ Github vì tôi vừa tìm thấy một lỗi trong stitch...)
Yihui Xie

7
Chỉ cần thêm 0,02 của tôi, nó cũng dễ dàng sử dụng chuyển hướng từ thiết bị đầu cuối. Một ví dụ là Rscript myfile.R > path/to/mylog.Routvà thay vì được in ra stdout (màn hình), đầu ra của tệp được lưu trong .Routtệp của bạn .
James Pringle

4
Để thêm vào @JamesPringle, tôi thường muốn đầu ra của mình được in cả trên màn hình (để theo dõi trong thời gian thực) và thành một tệp (để xem sau). Tôi làmRscript myfile.R | tee mylog.Rout
Heisenberg

26

Sau khi thử các tùy chọn được mô tả ở đây, tôi đã tìm thấy bài đăng này từ Forester trong r-blogger. Tôi nghĩ rằng đó là một lựa chọn sạch sẽ để xem xét.

Tôi đặt mã của anh ấy ở đây:

Từ dòng lệnh

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

Trong test.out

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

Cảm ơn Forester !


Điều quan trọng cần lưu ý, nếu các đối số có kiểu ký tự, không cần sử dụng dấu nháy đơn / kép. Ví dụ: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d

Như đã đề cập trong bài đăng của Forester, --argslà chìa khóa. Nó cũng hoạt động với R --no-save --no-restore --args a=1 < test.RR --no-save --no-restore < test.R --args a=1
Dave

Có cách nào để truyền đối số từ dòng lệnh vào --args không? Vì vậy, giả sử chúng ta muốn thực hiện một vòng lặp for trong dòng lệnh, và sau đó gửi nó trong dòng --args.
user2809432

9

Trong tập lệnh R của bạn, được gọi là test.R:

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

Từ dòng lệnh chạy:

R CMD BATCH -4 test.R

Tệp đầu ra của bạn, test.Rout, sẽ cho thấy rằng đối số 4đã được chuyển thành công đến 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 

8

Bạn cần đặt đối số trước my_script.Rvà sử dụng -đối số, ví dụ:

R CMD BATCH -blabla my_script.R

commandArgs()sẽ nhận -blabladưới dạng một chuỗi ký tự trong trường hợp này. Xem phần trợ giúp để biết chi tiết:

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

2
Tôi nhận thấy nếu tôi làm điều đó theo cách này và trong việc sử dụng kịch bản args <- commandArgs(FALSE)và sau đó in args, tôi kết thúc với tất cả các đối số, kể cả những người mà không phải là của tôi, giống như --restore, --save, vv Nếu tôi sử dụng commandArgs(TRUE)tôi nhận được không có đối số nào cả. Có cách nào để lấy các đối số bổ sung của riêng tôi không? --argstrông đầy hứa hẹn, nhưng tôi đã không thể để làm cho nó làm việc ...
Bryce Thomas

Bạn phải đếm các đối số từ cuối (ví dụ: size-2, size-1, size) - của bạn sẽ luôn ở cuối.
ynka

4

Tôi thêm câu trả lời vì tôi nghĩ rằng giải pháp một dòng luôn tốt! Trên đầu myRscript.Rtệp của bạn , thêm dòng sau:

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

Sau đó, gửi kịch bản của bạn với một cái gì đó như:

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

Ví dụ:

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

Sau đó:

> ls()
[1] "N"    "l"    "name"

0

Đây là một cách khác để xử lý args dòng lệnh, bằng cách sử dụng R CMD BATCH. Cách tiếp cận của tôi, dựa trên câu trả lời trước đó ở đây , cho phép bạn chỉ định các đối số tại dòng lệnh và trong tập lệnh R của bạn, cung cấp một số hoặc tất cả các giá trị mặc định.

Đây là tệp R, tôi đặt tên là 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)

Tại dòng lệnh, nếu tôi gõ

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

thì trong R chúng ta sẽ có a= 2b= c(2,5,6). Nhưng tôi có thể nói, bỏ qua bvà thêm vào một lập luận khác c:

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

Sau đó, trong R, chúng ta sẽ có a= 2, b= c(1,1,1)(mặc định) và c="hello" .

Cuối cùng, để thuận tiện, chúng ta có thể bọc mã R trong một hàm, miễn là chúng ta cẩn thận về môi trường:

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