我有一个名为foo的脚本。R包含另一个脚本other。R,在同一个目录下:

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

但我想让R找到另一个。R,不管当前工作目录是什么。

换句话说,就是foo。R需要知道自己的路径。我该怎么做呢?


当前回答

我喜欢这种方法:

this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)

其他回答

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

不要问我它是如何工作的,因为我已经忘记了:/

在我看来,从R脚本的获取路径中得到的rakensi的答案是最正确和真正精彩的。然而,它仍然是一个包含哑函数的黑客。我在这里引用它,是为了让别人更容易发现。

sourceDir <- getSrcDirectory(函数(dummy) {dummy})

这给出了放置语句的文件的目录(在那里定义了dummy函数)。然后可以使用它来设置工作目录并使用相对路径。

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

或者创建绝对路径

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

我在一个高性能计算集群环境中工作。我在不同的地方开发代码,而不是在生产运行的地方。在开发过程中,我通常从命令行交互式地调用R(而不是使用RStudio)。有很多来源(“foo.R”)正在进行。

在生产运行期间,我通常编写一个bash脚本,尝试不同的参数,并在单独的目录中运行每一组参数。bash脚本利用了工作负载管理器(即SLURM)。在这种环境中,设置环境变量很简单。考虑到这一点,下面的解决方案最适合我。

其他。R

my_message <- function(){
return("R is awkward")
}

foo。R

srcpath = Sys.getenv("R_SRC")
# Check if runnning w/o setting R_SRC - presumably done in directory of development, i.e. /path/to/R/code
if(srcpath == ""){
    srcpath="./"
}
source(sprintf("%s/other.R", srcpath))
string = my_message()
print(string)

如果从R交互式shell中运行,并且在/path/到/R/code中运行,那么简单

> source("foo.R")

如果不是从交互式shell运行,也不是从/path/to/R/code运行,首先设置环境变量R_SRC,然后调用Rscript

$ export R_SRC=/path/to/R/code/
$ Rscript /path/to/R/code/foo.R

这对我很有用。只是从命令行参数中greps它,去掉不需要的文本,执行dirname,最后从它获得完整的路径:

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

我喜欢steamer25的解决方案,因为它似乎是最健壮的。然而,当在RStudio中调试时(在windows中),路径不会被正确设置。原因是,如果在RStudio中设置了断点,那么源文件将使用另一个“调试源”命令,该命令将脚本路径设置得稍微不同。下面是我目前正在使用的最终版本,它解释了调试时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))
        }
    }
}