Rscript:确定正在执行的脚本的path
我有一个名为foo.R
脚本,它包含另一个脚本other.R
,它位于同一个目录中:
#!/usr/bin/env Rscript print("Hello") source("other.R")
但是我想R
find其他的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做的。