กำหนดเส้นทางของสคริปต์การดำเนินการ


255

ฉันมีสคริปต์ที่เรียกfoo.Rว่ารวมสคริปต์อื่นother.Rซึ่งอยู่ในไดเรกทอรีเดียวกัน:

#!/usr/bin/env Rscript
message("Hello")
source("other.R")

แต่ฉันต้องการRพบว่าother.Rไม่ว่าไดเรกทอรีทำงานปัจจุบัน

กล่าวอีกนัยหนึ่งfoo.Rจำเป็นต้องรู้เส้นทางของตัวเอง ฉันจะทำสิ่งนั้นได้อย่างไร


2
เลข :( ฉันไม่ได้เห็นวิธีการแก้ปัญหาใด ๆ ที่ใช้งานได้จริงนอกเหนือจากการแก้ปัญหาที่จะเพียงแค่ผ่านไดเรกทอรีหรือใช้ตัวแปรสภาพแวดล้อม..
แฟรงก์

3
สิ่งนี้น่าทึ่งมากที่ทำให้สคริปต์แบบพกพาและใช้งานได้แม้กับ neofites R!
Etienne Low-Décarie

4
ดูเหมือนว่าคำตอบทั้งหมดต้องการให้คุณป้อนเส้นทางในบางจุด (อย่างน้อยต้องแหล่งที่มาของไฟล์)! มันจะดีมากถ้าคุณสามารถส่งโฟลเดอร์บีบอัดให้ใครบางคนและเรียกใช้ไฟล์สคริปต์ R ภายในโฟลเดอร์นั้นจะอ่านและบันทึกลงในโฟลเดอร์นั้น
Etienne Low-Décarie

10
ปัญหาเดียวนี้จริง ๆ แล้วอาจกลายเป็นเหตุผลว่าทำไมฉันถึงย้ายไปยัง Python ได้อย่างสมบูรณ์
Giacomo

5
@giac_man ฉันรู้สึกว่า R เต็มไปด้วยปัญหาเล็ก ๆ น้อย ๆ เช่นนี้ที่ทำให้การทำงานยากขึ้น
Michael Barton

คำตอบ:


102

ที่นี่มีวิธีแก้ไขปัญหาง่ายๆ คำสั่งนี้:

script.dir <- dirname(sys.frame(1)$ofile)

ส่งคืนพา ธ ของไฟล์สคริปต์ปัจจุบัน ทำงานหลังจากบันทึกสคริปต์แล้ว


4
มันไม่ทำงานสำหรับฉัน ฉันรัน R ใน Windows ความคิดใด ๆ
Ehsan88

4
มีข้อผิดพลาดเดียวกันกับ scriptt ที่บันทึกไว้และติดตั้งใหม่และเรียกใช้ R 3.2.0 บน windows ...
RalfB

27
ข้อผิดพลาดนี้เกิดขึ้นเมื่อคุณพยายามเรียกใช้dirname(sys.frame(1)$ofile)โดยตรงจาก Rstudio มันทำงานได้ตกลงเมื่อสคริปต์จะถูกดำเนินการโดยใช้แหล่งกำเนิด ( "other.R") และอยู่ภายในdirname(sys.frame(1)$ofile) "other.R"
Murta

4
ฉันได้รับข้อผิดพลาด 'ไม่ว่ามีเฟรมจำนวนมากบนสแต็ก' เมื่อเรียกเป็นสคริปต์ที่มี rscript.exe นั่นคือไม่ได้ใช้ซอร์ส () ดังนั้นฉันจึงต้องใช้วิธีแก้ปัญหาจาก Suppressingfire ด้านล่างแทน
Mark Adamson

3
ฉันเจลNULLเมื่อสิ่งนี้ถูกวางไว้ในเซิร์ฟเวอร์ R เมื่อใช้ Shiny
Paul

75

คุณสามารถใช้commandArgsฟังก์ชั่นเพื่อให้ได้ตัวเลือกทั้งหมดที่ถูกส่งผ่านโดย Rscript กับ R --file=ล่ามที่เกิดขึ้นจริงและค้นหาพวกเขาสำหรับ หากสคริปต์ของคุณได้รับการเปิดตัวจากเส้นทางหรือถ้ามันถูกเปิดตัวด้วยเส้นทางที่เต็มด้านล่างนี้จะเริ่มต้นด้วยscript.name '/'มิฉะนั้นจะต้องสัมพันธ์กับcwdและคุณสามารถต่อสองเส้นทางเข้าด้วยกันเพื่อรับเส้นทางแบบเต็ม

แก้ไข:ดูเหมือนว่าคุณต้องการเพียงscript.nameด้านบนและเพื่อตัดองค์ประกอบสุดท้ายของเส้นทาง ผมเคยเอาออกไม่จำเป็นตัวอย่างและการทำความสะอาดขึ้นสคริปต์หลักและโพสต์ของฉันcwd() other.Rเพียงบันทึกออกสคริปต์นี้และother.Rสคริปต์ลงในไดเรกทอรีเดียวกันchmod +xพวกเขาและเรียกใช้สคริปต์หลัก

main.R :

#!/usr/bin/env Rscript
initial.options <- commandArgs(trailingOnly = FALSE)
file.arg.name <- "--file="
script.name <- sub(file.arg.name, "", initial.options[grep(file.arg.name, initial.options)])
script.basename <- dirname(script.name)
other.name <- file.path(script.basename, "other.R")
print(paste("Sourcing",other.name,"from",script.name))
source(other.name)

อื่น ๆ R :

print("hello")

ผลลัพธ์ :

burner@firefighter:~$ main.R
[1] "Sourcing /home/burner/bin/other.R from /home/burner/bin/main.R"
[1] "hello"
burner@firefighter:~$ bin/main.R
[1] "Sourcing bin/other.R from bin/main.R"
[1] "hello"
burner@firefighter:~$ cd bin
burner@firefighter:~/bin$ main.R
[1] "Sourcing ./other.R from ./main.R"
[1] "hello"

นี่คือสิ่งที่ฉันเชื่อว่า dehmann กำลังมองหา


อะไรคือ downmod?
ปราบปราม

2
ฉัน downmodded เพราะเทคนิคของคุณใช้ไม่ได้กับsourceที่ฉันคิดว่า OP ต้องการ - แต่บางทีฉันอาจเข้าใจผิดข้อกำหนดของเขา / เธอ แต่ฉันไม่สามารถคลายข้อผิดพลาดได้ :( ขออภัย!
hadley

แต่จริงๆแล้วมันทำงานได้ดีกับแหล่งที่มา! เพียงแค่แหล่งที่มา (other.name) และทำงานอย่างถูกต้อง
ปราบปราม

3
สำหรับการต่อข้อมูลทางที่ดีควรใช้other.name <- file.path(script.basename, "other.R")
Jason

1
เมื่อฉันพยายามที่จะเรียกใช้commandArgs(trailingOnly = FALSE)ภายใน server.R [1] "RStudio" "--interactive"ในการประยุกต์ใช้เงาที่ฉันได้รับ ไม่มีข้อมูลเกี่ยวกับไดเรกทอรีที่ถูกเรียกมา
Paul

57

ฉันไม่สามารถให้โซลูชันของ Suppressingfire ทำงานได้เมื่อ 'ซอร์ส' จากคอนโซล R
ฉันไม่สามารถรับโซลูชันของ Hadley ให้ทำงานได้เมื่อใช้ Rscript

ดีที่สุดของทั้งสองโลก?

thisFile <- function() {
        cmdArgs <- commandArgs(trailingOnly = FALSE)
        needle <- "--file="
        match <- grep(needle, cmdArgs)
        if (length(match) > 0) {
                # Rscript
                return(normalizePath(sub(needle, "", cmdArgs[match])))
        } else {
                # 'source'd via R console
                return(normalizePath(sys.frames()[[1]]$ofile))
        }
}

6
ฉันชอบสิ่งนี้เพราะมันใช้ได้กับทั้งสองRscriptและsource()ภายในอาร์ฉันแนะนำให้ทำnormalizePath()ทั้งสองเวอร์ชันเพื่อให้เส้นทางเต็มในทั้งสองกรณี
wch

1
นี่เป็นสิ่งเดียวที่ทำงานได้ หมายเหตุสำหรับการทำงานนี้library(base)ฉันใช้เวลาสักครู่เพื่อคิดออก lol
O.rka

2
คุณได้รับคะแนนของฉันเพราะนี่เป็นวิธีแก้ปัญหาที่ได้ผลสำหรับฉัน
Vince W.

1
ถ้านี้จะช่วยให้ทุกคนโพสต์เดิมที่จะหมายถึงในsource(file.path(dirname(thisFile()), "other.R")) foo.Rมันใช้งานได้สำหรับฉัน
Kim

ประเด็นหนึ่ง สมมติว่าใน RStudio ฉันแหล่งที่มาmain.Rซึ่งแหล่งที่มาที่โทรhelper.R thisFile()มันจะดึงข้อมูลเส้นทางของแทนmain.R helper.Rเคล็ดลับใด ๆ ที่นี่?
Wassadamo

37
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])

อย่าถามฉันว่ามันทำงานอย่างไรเพราะฉันลืม: /


2
บริบทนี้ทำงานอย่างไร พิมพ์ (sys.frames ()) เปลี่ยนเป็น NULL เมื่อฉันเรียกใช้
ปราบปราม

1
@Suppressingfire: sys.framesส่งคืนสภาพแวดล้อมของ call stack ดังนั้นมันจะสมเหตุสมผลจริงๆเมื่อถูกเรียกจากฟังก์ชั่น foo <- function() {bar <- function() print(sys.frames()); bar()}; foo()ลองเช่น ฉันไม่สามารถหารหัสของ @ hadley ได้เนื่องจากสภาพแวดล้อมไม่มีofileสมาชิก
Richie Cotton

1
คุณมีแหล่งไฟล์ใน - คือถ้าผมบันทึกรหัสที่ใช้แล้วsource("~/code/test.r"), จะถูกตั้งค่าPATH ~/desktopถ้าคุณแค่ประเมินมันที่ระดับบนสุดมันจะคืนค่า NULL
hadley

4
นี่ไม่ตอบคำถามของฉัน ฉันต้องการค้นหาไฟล์ "other.R" โดยอัตโนมัติ x$ofileไม่ได้กำหนดดังนั้นจึงframe_filesว่างเปล่า
Frank

@Hadley รหัสที่มีประโยชน์มาก ฉันสามารถสรุปฟังก์ชั่นยูทิลิตี้ "รีโหลดสคริปต์ปัจจุบัน" ฉันเพิ่มสคริปต์เกือบทั้งหมดเมื่อพวกเขาอยู่ในการพัฒนาที่ใช้งานอยู่ RScript reloader
Sim

29

มันใช้งานได้สำหรับฉัน

library(rstudioapi)    
rstudioapi::getActiveDocumentContext()$path

4
นี้ใช้งานได้จากภายใน RStudio ฉันเดา Error: RStudio not runningพยายามจากที่ฉันได้รับขั้ว
Ista

มันใช้งานได้ดีกว่านี้หากทำงานจากสคริปต์ R ในสตูดิโอ R แม้บนคอนโซลใน RStudio มันจะไม่ให้ผลลัพธ์ที่ถูกต้อง""ในกรณีของฉัน
Kay

นี้ทำงานได้ในขณะที่ทำงานที่สามารถโต้ตอบใน Rstudio ตราบใดที่คุณไม่เปลี่ยนเอกสารในโฟกัส หากคุณส่งบรรทัดที่จะเรียกใช้แล้วสลับไปที่เอกสารอื่นในขณะที่พวกเขาทำงานเส้นทางไปยังเอกสารอื่นจะถูกส่งกลับ
แพทริค

26

คำตอบของrakensiจากการหาเส้นทางของสคริปต์ Rเป็น IMHO ที่ถูกต้องและยอดเยี่ยมที่สุด กระนั้นก็ยังเป็นแฮ็คที่รวมฟังก์ชั่นหลอกตา ฉันอ้างถึงที่นี่เพื่อให้ผู้อื่นพบเจอได้ง่ายขึ้น

sourceDir <- getSrcDirectory (ฟังก์ชั่น (ดัมมี่) {ดัมมี่})

สิ่งนี้จะทำให้ไดเร็กตอรี่ของไฟล์ที่วางคำสั่ง (โดยที่ฟังก์ชัน dummy ถูกกำหนด) จากนั้นสามารถใช้เพื่อตั้งค่าไดเร็คทอรี่ที่ทำงานและใช้เส้นทางสัมพัทธ์เช่น

setwd(sourceDir)
source("other.R")

หรือเพื่อสร้างเส้นทางที่แน่นอน

 source(paste(sourceDir, "/other.R", sep=""))

1
สำหรับฉันทางออกของคุณดีที่สุด พิเศษเพราะมันสามารถนำไปใช้กับแอพ Shiny และอันนั้นบนลิงค์ไม่ได้
jcarlos

1
นี่คือ getSrcDirectory isils :: getSrcDirectory
RubenLaguna

5
สิ่งนี้อาจทำงานได้ดีบน Linux / Mac แต่มันไม่ได้ผลสำหรับฉันในเซสชัน RStudio ที่ทำงานร่วมกันใน Windows sourceDirว่างเปล่า
Contango

1
@Contango บนเทอร์มินัลแบบโต้ตอบไม่มีเส้นทาง !!! คุณต้องการพา ธ ไปยังไฟล์
pommedeterresautee

1
character(0)ฉันได้รับ ข้อเสนอแนะ?
หยุดงาน

16

ของฉันทั้งหมดในที่เดียว! (--01 / 09/2019 อัปเดตเพื่อจัดการกับคอนโซล RStudio)

#' current script file (in full path)
#' @description current script file (in full path)
#' @examples
#' works with Rscript, source() or in RStudio Run selection, RStudio Console
#' @export
ez.csf <- function() {
    # http://stackoverflow.com/a/32016824/2292993
    cmdArgs = commandArgs(trailingOnly = FALSE)
    needle = "--file="
    match = grep(needle, cmdArgs)
    if (length(match) > 0) {
        # Rscript via command line
        return(normalizePath(sub(needle, "", cmdArgs[match])))
    } else {
        ls_vars = ls(sys.frames()[[1]])
        if ("fileName" %in% ls_vars) {
            # Source'd via RStudio
            return(normalizePath(sys.frames()[[1]]$fileName))
        } else {
            if (!is.null(sys.frames()[[1]]$ofile)) {
            # Source'd via R console
            return(normalizePath(sys.frames()[[1]]$ofile))
            } else {
                # RStudio Run Selection
                # http://stackoverflow.com/a/35842176/2292993
                pth = rstudioapi::getActiveDocumentContext()$path
                if (pth!='') {
                    return(normalizePath(pth))
                } else {
                    # RStudio Console
                    tryCatch({
                            pth = rstudioapi::getSourceEditorContext()$path
                            pth = normalizePath(pth)
                        }, error = function(e) {
                            # normalizePath('') issues warning/error
                            pth = ''
                        }
                    )
                    return(pth)
                }
            }
        }
    }
}

ไม่สามารถใช้งานกับเซสชัน R แบบโต้ตอบได้ ฉันได้รับ: `` `> source (" csf.R ")> csf () ข้อผิดพลาด: RStudio ไม่ทำงาน` ``
ManicMailman

มันเยี่ยมมาก ใครสามารถสร้างแพ็คเกจได้บ้าง
Joe Flack

สิ่งนี้จะทำงานในขณะที่ทำงานแบบโต้ตอบใน Rstudio ตราบใดที่คุณไม่เปลี่ยนเอกสารในโฟกัส หากคุณส่งบรรทัดที่จะเรียกใช้แล้วสลับไปที่เอกสารอื่นในขณะที่พวกเขาทำงานเส้นทางไปยังเอกสารอื่นจะถูกส่งกลับ
แพทริค

13

ตัวแปรที่บางลงของคำตอบของ Supressingfire:

source_local <- function(fname){
    argv <- commandArgs(trailingOnly = FALSE)
    base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
    source(paste(base_dir, fname, sep="/"))
}

สิ่งนี้ไม่ทำงานซ้ำ แหล่งไฟล์ I ค้นหาไฟล์ข้อมูล (แต่อยู่ในไดเรกทอรีที่ไม่ถูกต้อง)
แมว Unfun

11

มันใช้งานได้สำหรับฉัน เพียงแค่ greps มันออกมาจากการขัดแย้งบรรทัดคำสั่งตัดข้อความที่ไม่ต้องการออก dirname และในที่สุดก็รับพา ธ แบบเต็มจากนั้น:

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))

8

ฉันได้ห่อขึ้นและขยายตอบของคำถามนี้เป็นฟังก์ชั่นใหม่thisfile()ในrprojroot knitrยังสามารถใช้ได้กับการถักไหมพรม


6

ฉันชอบวิธีการแก้ปัญหาของ steamer25 เพราะดูเหมือนว่าแข็งแกร่งที่สุดสำหรับวัตถุประสงค์ของฉัน อย่างไรก็ตามเมื่อทำการดีบั๊กใน RStudio (ใน windows) เส้นทางจะไม่ได้รับการตั้งค่าอย่างเหมาะสม เหตุผลที่ว่าถ้าเบรกพอยต์ตั้งอยู่ใน RStudio การจัดหาไฟล์จะใช้คำสั่ง "debug source" สำรองซึ่งกำหนดเส้นทางสคริปต์แตกต่างกันเล็กน้อย นี่คือรุ่นสุดท้ายที่ฉันใช้ในขณะนี้ซึ่งบัญชีสำหรับพฤติกรรมทางเลือกนี้ภายใน RStudio เมื่อแก้จุดบกพร่อง:

# @return full path to this script
get_script_path <- function() {
    cmdArgs = commandArgs(trailingOnly = FALSE)
    needle = "--file="
    match = grep(needle, cmdArgs)
    if (length(match) > 0) {
        # Rscript
        return(normalizePath(sub(needle, "", cmdArgs[match])))
    } else {
        ls_vars = ls(sys.frames()[[1]])
        if ("fileName" %in% ls_vars) {
            # Source'd via RStudio
            return(normalizePath(sys.frames()[[1]]$fileName)) 
        } else {
            # Source'd via R console
            return(normalizePath(sys.frames()[[1]]$ofile))
        }
    }
}

แหล่งที่มาใน Rstudio ให้ ofile สำหรับฉัน แต่ debugSource ให้ชื่อไฟล์ดังนั้นวิธีการแก้ปัญหาของคุณทำงานได้ดี แต่ความคิดเห็นของรหัสไม่ถูกต้องในกรณีของฉัน
Mark Adamson

6

ฉันลองเกือบทุกอย่างจากคำถามนี้การหาเส้นทางของสคริปต์ R , รับเส้นทางของสคริปต์ปัจจุบัน , ค้นหาตำแหน่งของไฟล์ปัจจุบัน. Rและคำสั่ง R สำหรับการตั้งค่าไดเรกทอรีทำงานไปยังตำแหน่งไฟล์ต้นฉบับใน Rstudioแต่ท้ายที่สุดก็พบว่าตนเอง เรียกดูตาราง CRAN และพบ

scriptName ห้องสมุด

ซึ่งให้current_filename()ฟังก์ชั่นซึ่งจะส่งกลับเส้นทางแบบเต็มของสคริปต์ที่เหมาะสมเมื่อจัดหาใน RStudio และเมื่อเรียกใช้ผ่านทาง R หรือ RScript ที่สามารถเรียกทำงานได้


2
Package ‘scriptName’ was removed from the CRAN repository.- แล้วตอนนี้ล่ะ? : o
Bojan P.

3

ฉันยังมีปัญหานี้และไม่มีวิธีแก้ไขปัญหาใดที่ได้ผลสำหรับฉัน อาจจะด้วยsourceหรือสิ่งต่าง ๆ เช่นนั้น แต่มันก็ไม่ชัดเจนพอ

ฉันพบสิ่งนี้สำหรับฉันวิธีแก้ปัญหา:

paste0(gsub("\\", "/", fileSnapshot()$path, fixed=TRUE),"/")

สิ่งสำคัญคือfileSnapshot()คุณให้ข้อมูลมากมายเกี่ยวกับไฟล์ มันส่งคืนรายการของ 8 องค์ประกอบ เมื่อคุณเลือกpathเป็นอิลิเมนต์รายการพา ธ จะถูกส่งคืนพร้อม\\ตัวคั่นดังนั้นโค้ดที่เหลือก็เพียงแค่เปลี่ยนมัน

ฉันหวังว่านี่จะช่วยได้.


1
สิ่งนี้ไม่ได้ผลสำหรับฉันบนเครื่อง Linux; แทนที่จะกลับเส้นทางของไฟล์มันกลับไดเรกทอรีที่ฉันอยู่ในปัจจุบันฉันสร้างสคริปต์ทดสอบชื่อ TEST.R ด้วยรหัสบรรทัดหนึ่ง: พิมพ์ (fileSnapshot () $ เส้นทาง) ฉันบันทึกไว้ในโฟลเดอร์นี้: / opt / home / boops / Desktop / Testfolder / TEST.RI จากนั้นไปที่เดสก์ท็อปของฉันและพยายามเรียกใช้ไฟล์: boops @ linuxserver: ~ / Desktop $ Rscript /opt/home/boops/Desktop/Testfolder/TEST.R [1 ] "/ opt / home / boops / Desktop"
Boops Boops

ไม่ได้ผลสำหรับฉันเช่นกัน ส่งคืนสิ่งเดียวกันกับ 'here ()' เมื่อใช้ไลบรารี 'here' มันส่งคืนพา ธ ไปยังโปรเจ็กต์ R ที่เปิดอยู่ในขณะนี้ แต่ไม่ใช่ว่าเขาจะถูกประหาร
Joe Flack

2

คุณสามารถล้อมสคริปต์ r ในสคริปต์ bash และดึงข้อมูลเส้นทางของสคริปต์เป็นตัวแปร bash ดังนี้:

#!/bin/bash
     # [environment variables can be set here]
     path_to_script=$(dirname $0)

     R --slave<<EOF
        source("$path_to_script/other.R")

     EOF

3
สิ่งนี้ต้องการให้คุณมีเส้นทางของสคริปต์ ไม่อนุญาตให้คุณสร้างสคริปต์ R แบบพกพาอย่างแท้จริงที่สามารถเรียกใช้ได้จากทุกที่
Etienne Low-Décarie

@ EtienneLow-Décarieมันไม่จำเป็นต้องใช้เส้นทางสคริปต์มันได้รับจากการทุบตี ปัญหาหลักคือมันไม่ใช่วิธีที่เชื่อถือได้ในการรับเส้นทาง สิ่งที่ต้องการเช่นนี้ในstackoverflow.com/questions/59895/… path_to_script = "$ (cd" $ (dirname "$ {BASH_SOURCE [0]}") "&& pwd)"
John Haberstroh


2

ฉันเพิ่งทำสิ่งนี้ด้วยตัวเอง เพื่อให้แน่ใจว่าความสามารถในการพกพาของสคริปต์ของคุณเริ่มต้นด้วย:

wd <- setwd(".")
setwd(wd)

มันทำงานได้เพราะ "." แปลว่าคำสั่ง Unix $ PWD การกำหนดสตริงนี้ให้กับวัตถุตัวอักษรจะช่วยให้คุณสามารถแทรกวัตถุตัวนั้นลงใน setwd () และPrestoรหัสของคุณจะทำงานกับไดเรกทอรีปัจจุบันเป็นไดเรกทอรีการทำงานเสมอไม่ว่าเครื่องจักรจะอยู่ที่ใดหรืออยู่ในโครงสร้างไฟล์ใด ที่ตั้งอยู่ (โบนัสพิเศษ: วัตถุ wd สามารถใช้กับ file.path () (เช่น. file.path (wd, "output_directory") เพื่ออนุญาตให้สร้างไดเรกทอรีส่งออกมาตรฐานโดยไม่คำนึงถึงเส้นทางไฟล์ที่นำไปสู่ไดเรกทอรีที่มีชื่อของคุณ สิ่งนี้ต้องการให้คุณสร้างไดเรกทอรีใหม่ก่อนที่จะอ้างอิงด้วยวิธีนี้ แต่คุณสามารถช่วยด้วยวัตถุ wd ได้เช่นกัน

อีกวิธีหนึ่งรหัสต่อไปนี้ทำสิ่งเดียวกัน:

wd <- getwd()
setwd(wd)

หรือถ้าคุณไม่ต้องการพา ธ ไฟล์ในวัตถุคุณสามารถทำได้ง่ายๆ

setwd(".")

11
Nope ที่ค้นหาไดเรกทอรีของกระบวนการไม่ใช่ตัวไฟล์เอง
user1071847

สิ่งนี้ใช้ได้กับฉันใน Windows ด้วย RStudio ในโหมดโต้ตอบ
Contango

2

โปรดทราบว่าแพคเกจ getopt มีget_Rscript_filenameฟังก์ชั่นซึ่งเพิ่งใช้โซลูชันเดียวกันที่นำเสนอที่นี่ แต่เขียนให้คุณแล้วในโมดูล R มาตรฐานดังนั้นคุณไม่ต้องคัดลอกและวางฟังก์ชัน "รับเส้นทางสคริปต์" ในทุกสคริปต์ ที่คุณเขียน.


มันจะส่งกลับค่า NA เสมอแม้ว่าฉันจะสร้างสคริปต์ที่พิมพ์เอาต์พุตแล้วก็เรียกสคริปต์เช่นด้วยR -e "library(getopt); testscript.R"
bokov

1
Rscriptในฐานะที่เป็นชื่อของฟังก์ชั่นที่แสดงถึงคุณจำเป็นต้องเรียกใช้สคริปต์ของคุณโดยใช้
Ryan C. Thompson

อ๊ะโอ๊ะโอ ขอบคุณ
bokov

1

ดูfindSourceTraceback()ของR.utilsแพคเกจซึ่ง

ค้นหาวัตถุ 'srcfile' ทั้งหมดที่สร้างโดย source () ในทุกเฟรมการโทร สิ่งนี้ทำให้เป็นไปได้ในการค้นหาว่าไฟล์ใดที่สคริปต์ถูกแหล่งโดย ()


1

ฉันมีปัญหากับการใช้งานด้านบนเนื่องจากสคริปต์ของฉันดำเนินการจากไดเรกทอรี symlinked หรืออย่างน้อยนั่นคือสาเหตุที่ฉันคิดว่าโซลูชันด้านบนไม่ได้ผลสำหรับฉัน ตามคำตอบของ @ ennuikiller ฉันห่อ Rscript ของฉันด้วยการทุบตี ฉันตั้งค่าตัวแปรพา ธ โดยใช้pwd -Pซึ่งแก้ไขโครงสร้างไดเรกทอรี symlinked จากนั้นผ่านเส้นทางเข้าไปใน Rscript

Bash.sh

#!/bin/bash

# set path variable
path=`pwd -P`

#Run Rscript with path argument
Rscript foo.R $path

foo.R

args <- commandArgs(trailingOnly=TRUE)
setwd(args[1])
source(other.R)

1

ฉันจะใช้วิธีการที่แตกต่างของ @ steamer25 ประเด็นก็คือฉันชอบที่จะได้รับสคริปต์ที่มาล่าสุดแม้ในขณะที่เซสชันของฉันเริ่มต้นด้วย Rscript ตัวอย่างต่อไปนี้เมื่อรวมอยู่ในไฟล์จะมีตัวแปรthisScriptที่มีเส้นทางปกติของสคริปต์ ฉันยอมรับการใช้ (ab) ของ source'ing ดังนั้นบางครั้งฉันจึงเรียกใช้ Rscript และสคริปต์ที่ให้ไว้ใน--fileแหล่งที่มาของการโต้แย้งสคริปต์อื่นที่มาอีกอันหนึ่ง ... สักวันหนึ่งฉันจะลงทุนในการทำให้โค้ดยุ่งของฉันกลายเป็นแพคเกจ

thisScript <- (function() {
  lastScriptSourced <- tail(unlist(lapply(sys.frames(), function(env) env$ofile)), 1)

  if (is.null(lastScriptSourced)) {
    # No script sourced, checking invocation through Rscript
    cmdArgs <- commandArgs(trailingOnly = FALSE)
    needle <- "--file="
    match <- grep(needle, cmdArgs)
    if (length(match) > 0) {
      return(normalizePath(sub(needle, "", cmdArgs[match]), winslash=.Platform$file.sep, mustWork=TRUE))
    }
  } else {
    # 'source'd via R console
    return(normalizePath(lastScriptSourced, winslash=.Platform$file.sep, mustWork=TRUE))
  }
})()

1

99% ของกรณีที่คุณอาจใช้เพียง:

sys.calls()[[1]] [[2]]

มันจะไม่ทำงานสำหรับการโทรบ้าที่สคริปต์ไม่ได้เป็นอาร์กิวเมนต์แรกเช่นsource(some args, file="myscript"). ใช้ @ hadley's ในกรณีแฟนซีเหล่านี้


ไม่ได้มาจากภายใน RStudio ยกเว้นเมื่อมีการจัดหา
nJGL

1

วิธีการของ Steamer25 ใช้งานได้เฉพาะในกรณีที่ไม่มีช่องว่างในเส้นทาง บน MacOS อย่างน้อยcmdArgs[match]สิ่งที่ผลตอบแทนเช่นสำหรับ/base/some~+~dir~+~with~+~whitespace//base/some\ dir\ with\ whitespace/

ฉันแก้ไขด้วยการแทนที่ "~ + ~" ด้วยช่องว่างที่เรียบง่ายก่อนส่งคืน

thisFile <- function() {
  cmdArgs <- commandArgs(trailingOnly = FALSE)
  needle <- "--file="
  match <- grep(needle, cmdArgs)
  if (length(match) > 0) {
    # Rscript
    path <- cmdArgs[match]
    path <- gsub("\\~\\+\\~", " ", path)
    return(normalizePath(sub(needle, "", path)))
  } else {
    # 'source'd via R console
    return(normalizePath(sys.frames()[[1]]$ofile))
  }
}

เห็นได้ชัดว่าคุณยังสามารถขยายบล็อกอื่นอย่างที่ aprstar ทำ


1

หากไม่ใช่สคริปต์foo.Rรู้ตำแหน่งของเส้นทางหากคุณสามารถเปลี่ยนรหัสของคุณเพื่ออ้างอิงsourceเส้นทางทั้งหมดจากจุดที่พบบ่อยrootสิ่งเหล่านี้อาจเป็นประโยชน์อย่างมาก:

ป.ร. ให้ไว้

  • /app/deeply/nested/foo.R
  • /app/other.R

สิ่งนี้จะได้ผล

#!/usr/bin/env Rscript
library(here)
source(here("other.R"))

ดูhttps://rprojroot.r-lib.org/สำหรับวิธีกำหนดรูทโปรเจ็กต์


สำหรับฉันแพ็คเกจที่นี่ทำหน้าที่ได้อย่างแน่นอนและดูเหมือนจะเป็นทางออกที่ง่าย
Ron

0
#!/usr/bin/env Rscript
print("Hello")

# sad workaround but works :(
programDir <- dirname(sys.frame(1)$ofile)
source(paste(programDir,"other.R",sep='/'))
source(paste(programDir,"other-than-other.R",sep='/'))

ฉันยังคงได้รับข้อผิดพลาด "ข้อผิดพลาดใน sys.frame (1): ไม่ใช่เฟรมจำนวนมากในสแต็ก"
Michael Barton

0

น่าทึ่งไม่มีโครงสร้างแบบ '$ 0' ใน R! คุณสามารถทำได้ด้วยการเรียก system () ไปที่สคริปต์ bash ที่เขียนด้วย R:

write.table(c("readlink -e $0"), file="scriptpath.sh",col=F, row=F, quote=F)
thisscript <- system("sh scriptpath.sh", intern = TRUE)

จากนั้นเพียงแยกชื่อ scriptpath.sh สำหรับ other.R

splitstr <- rev(strsplit(thisscript, "\\/")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")

ฉันได้รับข้อความแสดงข้อผิดพลาดreadLink: illegal option -- e usage: readLink [-FlLnqrsx] [-f format] [-t timefmt] [file ...]
altabq

0

โดยการดู call stack เราสามารถรับไฟล์พา ธ ของแต่ละสคริปต์ที่ถูกเรียกใช้งานได้ประโยชน์ที่สำคัญที่สุดสองอย่างอาจเป็นสคริปต์ที่กำลังเรียกใช้งานในปัจจุบันหรือสคริปต์แรกที่ต้องจัดหา (รายการ)

script.dir.executing = (function() return( if(length(sys.parents())==1) getwd() else dirname( Filter(is.character,lapply(rev(sys.frames()),function(x) x$ofile))[[1]] ) ))()

script.dir.entry = (function() return( if(length(sys.parents())==1) getwd() else dirname(sys.frame(1)$ofile) ))()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.