Fra*_*ank 234 r file path rscript r-faq
我有一个名为的脚本foo.R包含另一个脚本other.R,该脚本位于同一目录中:
#!/usr/bin/env Rscript
message("Hello")
source("other.R")
Run Code Online (Sandbox Code Playgroud)
但我想R发现other.R无论当前的工作目录是什么.
换句话说,foo.R需要知道自己的路径.我怎样才能做到这一点?
thi*_*ick 93
这里有一个简单的解决方案.这个命令:
script.dir <- dirname(sys.frame(1)$ofile)
Run Code Online (Sandbox Code Playgroud)
返回当前脚本文件的路径.保存脚本后它可以工作.
Sup*_*ire 67
您可以使用该commandArgs函数获取Rscript传递给实际R解释器的所有选项并搜索它们--file=.如果您的脚本是从路径启动的,或者它是以完整路径script.name启动的,则下面的内容将以a开头'/'.否则,它必须相对于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)
Run Code Online (Sandbox Code Playgroud)
其他.R:
print("hello")
Run Code Online (Sandbox Code Playgroud)
输出:
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"
Run Code Online (Sandbox Code Playgroud)
这就是我认为德曼正在寻找的东西.
ste*_*r25 55
当从R控制台'源'时,我无法让Suppressingfire的解决方案工作.
使用Rscript时,我无法让hadley的解决方案工作.
两全其美?
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))
}
}
Run Code Online (Sandbox Code Playgroud)
had*_*ley 35
frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])
Run Code Online (Sandbox Code Playgroud)
不要问我它是如何工作的,因为我忘记了:/
cuf*_*fel 24
来自R脚本的获取路径的rakensi的答案是最正确和非常精彩的恕我直言.然而,它仍然是一个包含虚拟功能的黑客.我在这里引用它,以便让别人更容易找到它.
sourceDir < - getSrcDirectory(function(dummy){dummy})
这给出了放置语句的文件的目录(定义了伪函数的位置).然后它可以用于设置工作目标并使用相对路径,例如
setwd(sourceDir)
source("other.R")
Run Code Online (Sandbox Code Playgroud)
或创建绝对路径
source(paste(sourceDir, "/other.R", sep=""))
Run Code Online (Sandbox Code Playgroud)
小智 21
这适合我
library(rstudioapi)
rstudioapi::getActiveDocumentContext()$path
Run Code Online (Sandbox Code Playgroud)
mom*_*ara 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="/"))
}
Run Code Online (Sandbox Code Playgroud)
Jer*_*y T 12
我的一体!( - 01/09/2011更新以处理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)
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 9
这适合我.只需从命令行参数中获取它,剥离不需要的文本,执行一个dirname,最后从中获取完整路径:
args <- commandArgs(trailingOnly = F)
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
Run Code Online (Sandbox Code Playgroud)
截至 2020 年 11 月 11 日,我在 CRAN 上为此制作了一个名为“this.path”的软件包(截至 2021 年 3 月 21 日,最新版本为 0.4.4)。
使用以下方法安装它:
install.packages("this.path")
然后通过以下方式使用它:
this.path::this.path()
或者
图书馆(this.path)
this.path()
下面的答案是我的原始答案,仅供参考,尽管它的功能比 CRAN 上可用的最新版本要少得多。改进包括:
base::source参数chdir设置为时正确规范化路径TRUEbase::source(即“文件://绝对或相对路径”和“文件:///绝对路径”)base::sourcetestthat::source_filethis.path在脚本中第一次调用时将规范化路径保存在其适当的环境中,从而可以更快地在同一脚本中使用后续时间并且独立于工作目录。这意味着在使用相对路径或从 Windows 命令行运行 R时setwd不会再中断// Unix 终端(只要在第一次调用该脚本后使用)this.pathbase::sourcesetwdthis.path原答案:
我的回答是对 Jerry T 回答的改进。我发现的问题是他们source通过检查是否ofile在堆栈的第一帧中找到变量来猜测是否进行了调用。这不适用于嵌套的源调用,也不适用于从非全局环境进行的源调用。此外,顺序是错误的。我们必须在检查命令行参数之前查找源调用。这是我的解决方案:
this.path <- function (verbose = getOption("verbose"))
{
where <- function(x) if (verbose)
cat("Source: ", x, "\n", sep = "")
# loop through functions that lead here from most recent to earliest looking
# for an appropriate source call (a call to function base::source or base::sys.source)
# an appropriate source call is a source call in which
# argument 'file' has been evaluated (forced)
# this means, for example, the following is an inappropriate source call:
# source(this.path())
# the argument 'file' is stored as a promise
# containing the expression "this.path()"
# when the value of 'file' is requested, it assigns the value
# returned by evaluating "this.path()" to variable 'file'
# there are two functions on the calling stack at
# this point being 'source' and 'this.path'
# clearly, you don't want to request the 'file' argument from that source
# call because the value of 'file' is under evaluation right now!
# the trick is to ask if variable ('ofile' for base::source, 'exprs' for base::sys.source)
# exists in that function's evaluation environment. this is because that
# variable is created AFTER argument 'file' has been forced
# if that variable does exist, then argument 'file' has been forced and the
# source call is deemed appropriate. For base::source, the filename we want
# is the variable 'ofile' from that function's evaluation environment. For
# base::sys.source, the filename we want is the variable 'file' from that
# function's evaluation environment.
# if that variable does NOT exist, then argument 'file' hasn't been forced and
# the source call is deemed inappropriate. The 'for' loop moves to the next
# function up the calling stack (if available)
#
# unfortunately, there is no way to check the argument 'fileName' has been forced
# for 'debugSource' since all the work is done internally in C. Instead,
# we have to use a 'tryCatch' statement. When we ask for an object by name
# using 'get', R is capable of realizing if a variable is asking for its
# own definition (a recursive definition). The exact error is "promise already
# under evaluation" which indicates that the promise evaluation is requesting
# its own value. So we use the 'tryCatch' to get the argument 'fileName'
# from the evaluation environment of 'debugSource', and if it does not raise
# an error, then we are safe to return that value. If not, the condition
# returns false and the 'for' loop moves to the next function up the calling
# stack (if available)
if (.Platform$GUI == "RStudio")
dbs <- get("debugSource", mode = "function", "tools:rstudio",
inherits = FALSE)
for (n in seq.int(sys.nframe(), 1L)[-1L]) {
if (identical(sys.function(n), base::source) &&
exists("ofile", envir = sys.frame(n), inherits = FALSE)) {
path <- get("ofile", envir = sys.frame(n), inherits = FALSE)
if (!is.character(path))
path <- summary.connection(path)$description
where("call to function source")
return(normalizePath(path, mustWork = TRUE))
}
else if (identical(sys.function(n), base::sys.source) &&
exists("exprs", envir = sys.frame(n), inherits = FALSE)) {
path <- get("file", envir = sys.frame(n), inherits = FALSE)
where("call to function sys.source")
return(normalizePath(path, mustWork = TRUE))
}
else if (.Platform$GUI == "RStudio" && identical(sys.function(n), dbs) &&
tryCatch({
path <- get("fileName", envir = sys.frame(n), inherits = FALSE)
TRUE
}, error = function(c) FALSE)) {
where("call to function debugSource in RStudio")
return(normalizePath(path, mustWork = TRUE))
}
}
# if the for loop is passed, no appropriate
# source call was found up the calling stack
# next, check if the user is running R from the command-line
# on a Windows OS, the GUI is "RTerm"
# on a Unix OS, the GUI is "X11"
if (.Platform$OS.type == "windows" && .Platform$GUI == "RTerm" || # running from Windows command-line
.Platform$OS.type == "unix" && .Platform$GUI == "X11") { # running from Unix command-line
# get all command-line arguments that start with "--file="
# check the number of command-line arguments starting with "--file="
# in case more or less than one were supplied
path <- grep("^--file=", commandArgs(), value = TRUE)
if (length(path) == 1L) {
path <- sub("^--file=", "", path)
where("Command-line argument 'FILE'")
return(normalizePath(path, mustWork = TRUE))
}
else if (length(path)) {
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from the command-line where formal argument 'FILE' matched by multiple actual arguments")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from the command-line where argument 'FILE' is missing")
}
else if (.Platform$GUI == "RStudio") { # running R from 'RStudio'
# function ".rs.api.getActiveDocumentContext" from the environment "tools:rstudio"
# returns a list of information about the document where your cursor is located
#
# function ".rs.api.getSourceEditorContext" from the environment "tools:rstudio"
# returns a list of information about the document open in the current tab
#
# element 'id' is a character string, an identification for the document
# element 'path' is a character string, the path of the document
adc <- get(".rs.api.getActiveDocumentContext",
mode = "function", "tools:rstudio", inherits = FALSE)()
if (adc$id != "#console") {
path <- adc$path
if (nzchar(path)) {
where("active document in RStudio")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* active document in RStudio does not exist")
}
sec <- get(".rs.api.getSourceEditorContext", mode = "function",
"tools:rstudio", inherits = FALSE)()
if (!is.null(sec)) {
path <- sec$path
if (nzchar(path)) {
where("source document in RStudio")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* source document in RStudio does not exist")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from RStudio with no documents open")
}
else if (.Platform$OS.type == "windows" && .Platform$GUI == "Rgui") { # running R from 'RGui' on Windows
# on a Windows OS only, the function "getWindowsHandles" from the base
# package "utils" returns a list of external pointers containing the windows
# handles. The thing of interest are the names of this list, these should
# be the names of the windows belonging to the current R process. Since
# RGui can have files besides R scripts open (such as images), a regular
# expression is used to subset only windows handles with names that exactly
# match the string "R Console" or end with " - R Editor". I highly suggest
# that you NEVER end a document's filename with " - R Editor". From there,
# similar checks are done as in the above section for 'RStudio'
wh <- names(utils::getWindowsHandles(pattern = "^R Console$| - R Editor$",
minimized = TRUE))
if (!length(wh))
stop("no windows in RGui; should never happen, please report!")
path <- wh[1L]
if (path != "R Console") {
path <- sub(" - R Editor$", "", path)
if (path != "Untitled") {
where("active document in RGui")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* active document in RGui does not exist")
}
path <- wh[2L]
if (!is.na(path)) {
path <- sub(" - R Editor$", "", path)
if (path != "Untitled") {
where("source document in RGui")
return(normalizePath(path, mustWork = TRUE))
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* source document in RGui does not exist")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from RGui with no documents open")
}
else if (.Platform$OS.type == "unix" && .Platform$GUI == "AQUA") { # running R from 'RGui' on Unix
stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run from AQUA which requires a source call on the calling stack")
}
else stop("'this.path' used in an inappropriate fashion\n",
"* no appropriate source call was found up the calling stack\n",
"* R is being run in an unrecognized manner")
}
Run Code Online (Sandbox Code Playgroud)
小智 6
我喜欢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))
}
}
}
Run Code Online (Sandbox Code Playgroud)
我从这个问题尝试了几乎所有方法,获取R脚本的路径,获取当前脚本的路径,查找当前.R文件的位置以及用于在Rstudio中将工作目录设置为源文件位置的R命令,但最后还是手动找到了自己浏览CRAN表并找到
scriptName 图书馆
它提供current_filename()功能,当在RStudio中进行采购以及通过R或RScript可执行文件进行调用时,该函数将返回脚本的正确完整路径。
您可以将 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
105364 次 |
| 最近记录: |