Rscript:确定正在执行的脚本的path

我有一个名为foo.R脚本,它包含另一个脚本other.R ,它位于同一个目录中:

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

但是我想Rfind其他的other.R无论目前的工作目录。

换句话说, foo.R需要知道自己的path。 我怎样才能做到这一点?

这里有一个简单的解决scheme。 这个命令:

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

返回当前脚本文件的path。 它在脚本被保存之后起作用。

您可以使用commandArgs函数来获取Rscript传递给实际R解释器的所有选项,并search它们的--file= 。 如果您的脚本是从path启动的,或者是以完整path启动的,则下面的script.name将以'/'开头。 否则,它必须是相对于cwd ,你可以连接两个path来获得完整的path。

编辑:这听起来像你只需要上面的script.name并剥离path的最后组件。 我已经删除了不需要的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 <- paste(sep="/", 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" 

这是我相信德曼正在寻找的东西。

 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控制台input信号时,我无法得到Suppressingfire的解决scheme。
使用Rscript时,我无法得到hadley的解决scheme。

两全其美?

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

Supressingfire的减肥方法是:

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

从R脚本获得path rakensi的答案是最正确和真正的辉煌恕我直言。 然而,它仍然是一个虚拟function的破解。 我在这里引用它是为了让别人更容易find它。

sourceDir < – getSrcDirectory(function(dummy){dummy})

这给出了放置语句的文件的目录(虚函数被定义的地方)。 它可以用来设置工作方向,并使用相对path,例如

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

或创build绝对path

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

这对我有用。 只是从命令行参数中删除它,去除不需要的文本,做一个dirname,最后得到完整的path:

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

我喜欢steamer25的解决scheme,因为它似乎是最强大的我的目的。 但是,在RStudio中(在Windows中)debugging时,path无法正确设置。 原因是如果在RStudio中设置了断点,源文件使用一个替代的“debugging源”命令来设置脚本path有点不同。 下面是我正在使用的最终版本,它在RStudio中debugging时考虑了这种替代行为:

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

我已经把这个问题的答案包含并扩展成了一个新的函数thisfile()在我的misc包中 。 也适用于knitr针织。

我的一切都在一个!

 #' current script file (in full path) #' @param #' @return #' @examples #' works with Rscript, source() or in RStudio Run selection #' @export 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 return(normalizePath(rstudioapi::getActiveDocumentContext()$path)) } } } } 

我只是自己做了这个。 为确保脚本的可移植性,请始终使用以下命令:

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

这是因为“。” 像Unix命令$ PWD一样转换。 将这个string赋值给一个字符对象允许你将这个字符对象插入到setwd()中,并且你的代码将总是以当前目录作为工作目录运行,不pipe它在哪个机器上或者在哪个文件结构中位于。 (额外的好处:wd对象可以与file.path()(即file.path(wd,“output_directory”)一起使用,以允许创build标准输出目录,而不pipe文件path通往指定的目录。这确实需要你在引用它之前创build新的目录,但是也可以用wd对象来帮助。

或者,下面的代码执行完全相同的事情:

 wd <- getwd() setwd(wd) 

或者,如果您不需要对象中的文件path,则可以简单地:

 setwd(".") 

您可以将r脚本包装在bash脚本中,并像下面这样获取脚本的path:

 #!/bin/bash # [environment variables can be set here] path_to_script=$(dirname $0) R --slave<<EOF source("$path_to_script/other.R") EOF 

我喜欢这种方法:

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

请参阅findSourceTraceback()包的findSourceTraceback()

查找所有调用帧中由source()生成的所有“srcfile”对象。 这使得可以找出哪些文件是由source()编写的。

我遇到了上述实现的问题,因为我的脚本是从symlinked目录下运行的,至less这就是为什么我认为上述解决scheme对我不起作用。 顺着@ennuikiller的回答,我用bash包装了我的Rscript。 我使用pwd -P来设置pathvariables,它parsing了符号链接的目录结构。 然后将path传入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) 

我会使用@ steamer25的方法的变种。 重点是,即使我的会话是通过Rscript启动,我更愿意获取最后一个源脚本。 以下代码片段包含在文件中时,将提供一个variablesthisScript其中包含脚本的规范化path。 我承认(使用)源代码,所以有时候我会调用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)) } })() 

请注意,getopt包提供了get_Rscript_filename函数, get_Rscript_filename使用了与此处介绍的相同的解决scheme,但已经在标准R模块中为您编写,因此您不必将“获取脚本path”function复制并粘贴到每个你写的脚本。

这对我有用

 library(rstudioapi) rstudioapi::getActiveDocumentContext()$path 
 #!/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='/')) 

99%的情况下你可以简单地使用:

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

如果脚本不是第一个参数,也就是source(some args, file="myscript") ,那么这个函数就不会工作。 在这些奇特的案例中使用@哈德利。

蒸笼25的方法是有效的,但是只有在path中没有空白的情况下。 在macOS上,至lesscmdArgs[match]返回类似/base/some~+~dir~+~with~+~whitespace/ cmdArgs[match] /base/some~+~dir~+~with~+~whitespace/ for /base/some\ dir\ with\ whitespace/

我通过在返回之前用一个简单的空格replace“〜+〜”来解决这个问题。

 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做的。