ส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่งไปยัง R CMD BATCH


102

ฉันใช้R CMD BATCH my_script.Rจากเทอร์มินัลเพื่อเรียกใช้Rสคริปต์ ตอนนี้ฉันอยู่ในจุดที่ฉันต้องการส่งต่อข้อโต้แย้งไปยังคำสั่ง แต่กำลังมีปัญหาบางอย่างในการทำให้มันใช้งานได้ ถ้าผมทำR CMD BATCH my_script.R blablaแล้วblablaจะกลายเป็นไฟล์ที่ส่งออกมากกว่าการถูกตีความว่าเป็นข้อโต้แย้งที่มีอยู่ไปยังสคริปต์ R ที่กำลังดำเนินการ

ฉันได้ลองRscript my_script.R blablaซึ่งดูเหมือนว่าจะส่งต่อblablaอย่างถูกต้องเป็นอาร์กิวเมนต์ แต่ฉันไม่ได้รับmy_script.Routไฟล์เอาต์พุตที่ฉันได้รับR CMD BATCH(ฉันต้องการ.Routไฟล์) ในขณะที่ฉันสามารถเปลี่ยนทิศทางผลลัพธ์ของการโทรไปRscriptยังชื่อไฟล์ที่ฉันเลือก แต่ฉันจะไม่ได้รับคำสั่งอินพุต R ที่รวมอยู่ในไฟล์ในลักษณะที่R CMD BATCHทำใน.Routไฟล์

โดยหลักการแล้วฉันใช้วิธีส่งอาร์กิวเมนต์ไปยังสคริปต์ R ที่ดำเนินการผ่านR CMD BATCHวิธีการนี้แม้ว่าจะมีความสุขกับวิธีการที่ใช้Rscriptหากมีวิธีที่จะทำให้มันสร้าง.Routไฟล์ที่เทียบเคียงได้

คำตอบ:


114

ความประทับใจของฉันคือมันR CMD BATCHเป็นเรื่องเล็กน้อย ไม่ว่าในกรณีใดการRscriptเรียกใช้งานล่าสุด(พร้อมใช้งานในทุกแพลตฟอร์ม) พร้อมกับcommandArgs()ทำให้อาร์กิวเมนต์บรรทัดคำสั่งการประมวลผลค่อนข้างง่าย

ตัวอย่างเช่นนี่คือสคริปต์เล็ก ๆ น้อย ๆ - เรียกมันว่า"myScript.R":

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

และนี่คือสิ่งที่เรียกใช้จากบรรทัดคำสั่งดูเหมือนว่า

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

แก้ไข:

ไม่ใช่ว่าฉันจะแนะนำ แต่ ... ใช้การรวมกันsource()และsink()คุณสามารถRscriptสร้าง.Routไฟล์แบบที่สร้างโดยR CMD BATCH. วิธีหนึ่งคือสร้างสคริปต์ R เล็ก ๆ - เรียกว่า RscriptEcho.R - ซึ่งคุณเรียกโดยตรงกับ Rscript อาจมีลักษณะดังนี้:

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

ในการรันสคริปต์จริงของคุณคุณจะต้องทำ:

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

ซึ่งจะดำเนินการกับข้อโต้แย้งจัดหาและจมอินพุตอัดเอาท์พุทและข้อความที่จะมีชื่อไม่ซ้ำกันmyScript.R.Rout

แก้ไข 2:
คุณสามารถเรียกใช้ Rscript แบบละเอียดและวางเอาต์พุต verbose ในไฟล์

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

4
ฉันยังได้รับความประทับใจR CMD BATCHเป็นของที่ระลึก สิ่งที่ฉันชอบเกี่ยวกับเรื่องนี้คือมันสร้าง.Routไฟล์ที่ไม่ได้มีแค่เอาต์พุตสคริปต์เท่านั้น แต่ยังรวมคำสั่ง / ความคิดเห็นอินพุตจาก.Rไฟล์สคริปต์ที่สร้างเอาต์พุตนั้นด้วย
Bryce Thomas

1
ฉันได้ยินคุณ. นั่นคือ (ผมเดาว่าคงเป็น!) R CMD BATCHเป็นลักษณะที่ดีของ
Josh O'Brien

5
แต่ฉันคิดว่าคุณทำได้ดีกว่าR CMD BATCHด้วยknitrเช่นRscript -e "knitr::stitch(commandArgs(TRUE)[1])" my_script.R(คุณสามารถแทนที่stitchด้วยstitch_rhtmlหรือstitch_rmdและคุณต้องติดตั้งknitrจากGithubเนื่องจากฉันเพิ่งพบข้อผิดพลาดในstitch... )
Yihui Xie

7
เพียงแค่เพิ่ม 0.02 ของฉันก็ยังใช้การเปลี่ยนเส้นทางจากเทอร์มินัลได้อย่างง่ายดาย ตัวอย่างคือRscript myfile.R > path/to/mylog.Routแทนที่จะพิมพ์เป็น stdout (หน้าจอ) เอาต์พุตของไฟล์จะถูกบันทึกไว้ใน.Routไฟล์ของคุณ
James Pringle

4
ในการเพิ่มไปยัง @JamesPringle ฉันมักต้องการให้ผลลัพธ์ของฉันพิมพ์บนหน้าจอ (เพื่อตรวจสอบแบบเรียลไทม์) และลงในไฟล์ (เพื่อดูในภายหลัง) ฉันทำRscript myfile.R | tee mylog.Rout
Heisenberg

26

หลังจากลองใช้ตัวเลือกที่อธิบายไว้ที่นี่ฉันพบโพสต์นี้จาก Forester ใน r-bloggers ฉันคิดว่ามันเป็นตัวเลือกที่สะอาดที่ควรพิจารณา

ฉันใส่รหัสของเขาที่นี่:

จากบรรทัดคำสั่ง

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

ทดสอบ

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

ใน test.out

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

ขอบคุณForester !


สิ่งสำคัญที่ควรทราบหากอาร์กิวเมนต์เป็นอักขระประเภทไม่จำเป็นต้องใช้เครื่องหมายคำพูดเดี่ยว / คู่ เช่น: R CMD BATCH '--args a = FolderName' test.R test.out &
d2a2d

ดังที่กล่าวไว้ในโพสต์ของ Forester --argsเป็นกุญแจสำคัญ นอกจากนี้ยังทำงานร่วมกับR --no-save --no-restore --args a=1 < test.RและR --no-save --no-restore < test.R --args a=1
Dave

มีวิธีส่งอาร์กิวเมนต์จากบรรทัดคำสั่งไปยัง --args หรือไม่? สมมติว่าเราต้องการทำ for loop ในบรรทัดคำสั่งจากนั้นส่งในบรรทัด --args
user2809432

9

ในสคริปต์ R ของคุณเรียกว่าtest.R:

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

จากบรรทัดคำสั่งให้รัน:

R CMD BATCH -4 test.R

ไฟล์ผลลัพธ์ของคุณ test.Rout จะแสดงว่าอาร์กิวเมนต์4ถูกส่งผ่านไปยัง 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

คุณต้องใส่อาร์กิวเมนต์ก่อนmy_script.Rและใช้-กับอาร์กิวเมนต์เช่น

R CMD BATCH -blabla my_script.R

commandArgs()จะได้รับ-blablaเป็นสตริงอักขระในกรณีนี้ ดูความช่วยเหลือสำหรับรายละเอียด:

$ 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
ผมสังเกตเห็นว่าถ้าผมทำมันด้วยวิธีนี้และในการใช้งานสคริปต์args <- commandArgs(FALSE)แล้วพิมพ์ args ผมจบลงด้วยข้อโต้แย้งทั้งหมดรวมทั้งผู้ที่ไม่ได้เหมืองเช่น--restore, --saveฯลฯ หากผมใช้commandArgs(TRUE)ผมได้รับข้อโต้แย้งที่ไม่ทั้งหมด มีวิธีรับข้อโต้แย้งเพิ่มเติมของตัวเองหรือไม่? --argsดูมีแนวโน้ม แต่ฉันยังไม่สามารถใช้งานได้ ...
Bryce Thomas

คุณต้องนับอาร์กิวเมนต์จากจุดสิ้นสุด (เช่น size-2, size-1, size) - ของคุณจะอยู่ที่ส่วนท้ายเสมอ
ynka

4

ฉันเพิ่มคำตอบเพราะฉันคิดว่าวิธีแก้ปัญหาแบบบรรทัดเดียวนั้นดีเสมอ! ที่ด้านบนของmyRscript.Rไฟล์ของคุณให้เพิ่มบรรทัดต่อไปนี้:

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

จากนั้นส่งสคริปต์ของคุณด้วยสิ่งต่างๆเช่น:

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

ตัวอย่างเช่น:

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

จากนั้น:

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

0

นี่คือวิธีการที่จะดำเนินการ args R CMD BATCHบรรทัดคำสั่งอื่นใช้ แนวทางของฉันซึ่งสร้างจากคำตอบก่อนหน้านี้ช่วยให้คุณระบุอาร์กิวเมนต์ที่บรรทัดคำสั่งและในสคริปต์ R ของคุณให้ค่าเริ่มต้นบางส่วนหรือทั้งหมด

นี่คือไฟล์ R ที่ฉันตั้งชื่อว่า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)

ที่บรรทัดคำสั่งถ้าฉันพิมพ์

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

แล้วภายใน R เราจะมีa= 2และ=b c(2,5,6)แต่ฉันสามารถพูดละเว้นbและเพิ่มข้อโต้แย้งอื่นc:

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

จากนั้นใน R เราจะมีa= 2, b= c(1,1,1)(ค่าเริ่มต้น) และ=c"hello"

สุดท้ายเพื่อความสะดวกเราสามารถรวมรหัส R ไว้ในฟังก์ชันได้ตราบใดที่เราระมัดระวังเกี่ยวกับสภาพแวดล้อม:

## 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)))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.