我有一个名为foo的脚本。R包含另一个脚本other。R,在同一个目录下:
#!/usr/bin/env Rscript
message("Hello")
source("other.R")
但我想让R找到另一个。R,不管当前工作目录是什么。
换句话说,就是foo。R需要知道自己的路径。我该怎么做呢?
我有一个名为foo的脚本。R包含另一个脚本other。R,在同一个目录下:
#!/usr/bin/env Rscript
message("Hello")
source("other.R")
但我想让R找到另一个。R,不管当前工作目录是什么。
换句话说,就是foo。R需要知道自己的路径。我该怎么做呢?
当前回答
只是在上面的答案的基础上,作为安全检查,您可以添加一个包装器,当sys.frame(1)失败时(如果interactive() == TRUE可能会失败),或者源脚本不在主脚本所期望的位置时,它会要求用户找到文件。
fun_path = tryCatch(expr =
{file.path(dirname(sys.frame(1)$ofile), "foo.R")},
error = function(e){'foo.R'}
)
if(!file.exists(fun_path))
{
msg = 'Please select "foo.R"'
# ask user to find data
if(Sys.info()[['sysname']] == 'Windows'){#choose.files is only available on Windows
message('\n\n',msg,'\n\n')
Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
fun_path = choose.files(
default = file.path(gsub('\\\\', '/', Sys.getenv('USERPROFILE')),#user
'Documents'),
caption = msg
)
}else{
message('\n\n',msg,'\n\n')
Sys.sleep(0.5)#goes too fast for the user to see the message on some computers
fun_path = file.choose(new=F)
}
}
#source the function
source(file = fun_path,
encoding = 'UTF-8')
其他回答
你可以在一个bash脚本中包装r脚本,并检索脚本的路径作为bash变量,如下所示:
#!/bin/bash
# [environment variables can be set here]
path_to_script=$(dirname $0)
R --slave<<EOF
source("$path_to_script/other.R")
EOF
当从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))
}
}
这对我很有用。只是从命令行参数中greps它,去掉不需要的文本,执行dirname,最后从它获得完整的路径:
args <- commandArgs(trailingOnly = F)
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
通过查看调用堆栈,我们可以获得正在执行的每个脚本的文件路径,其中最有用的两个可能是当前正在执行的脚本,或者是要获取的第一个脚本(条目)。
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) ))()
I would use a variant of @steamer25 's approach. The point is that I prefer to obtain the last sourced script even when my session was started through Rscript. The following snippet, when included on a file, will provided a variable thisScript containing the normalized path of the script. I confess the (ab)use of source'ing, so sometimes I invoke Rscript and the script provided in the --file argument sources another script that sources another one... Someday I will invest in making my messy code turns into a package.
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))
}
})()