获取R脚本的路径


68

是否可以通过编程方式在脚本本身内部找到R脚本的路径?

我之所以这样问是因为我有几个使用RGtk2和加载.glade文件中的GUI的脚本。

在这些脚本中,我必须setwd("path/to/the/script")在开头添加一条指令,否则将找不到.glade文件(位于同一目录中)。

很好,但是如果我将脚本移动到其他目录或另一台计算机,则必须更改路径。我知道,这没什么大不了的,但是拥有这样的东西会很好:

setwd(getScriptPath())

那么,是否存在类似的功能?


1
这在交互式会话中(例如在使用Rstudio时)特别有用。
Quantum7

1
看来,许多“文件路径”问题现在都可以使用rprojroot软件包解决:cran.r-project.org/web/packages/rprojroot/index.html。rprojroot自称“ rprojroot:在项目子目录中查找文件”。可交互使用的“轻量级”版本是here软件包:github.com/krlmlr/here
BarkleyBG

1
@BarkleyBG(here软件包)提供的解决方案对我来说非常有效。
MauOlivares

Answers:


26

采用 source("yourfile.R", chdir = T)


2
@nico我是R的新手,我想做类似的事情。我尝试了此解决方案,但出现错误Error: '...' used in an incorrect context,请您说明可能是什么问题?
Dronacharya

28
这不是广泛适用,尤其是对于问题的标题而言-不能从脚本本身内部使用-如果您知道路径(用于获取文件),则显然也可以设置路径。
鲁本

3
@hadley这就是我的工作。不幸的是,这种假设并不总能奏效(尤其是在使用时source。在交互式会话中,不正确的工作目录使我与非技术同事共享.r,.rmd等非常麻烦,他们会打开我发送的.r脚本并在执行所有行时设置先前的WD设置,因此相对路径会失败。因此,类似__DIR__PHP的东西会很有用,但是,如果可能的话,很容易。
鲁本

2
@hadley其实他们没有。项目将WD设置为项目目录,该目录与项目子文件夹中的源文件不同。因此,我将为Rstudio项目使用的相对路径将与那些knitr的使用有所不同。但是,最重要的是,如果更改了wd,则无法以编程方式将wd重置为适当的值。我对此提出了建议。对于此功能的归属,我没有坚定的信念,但这很麻烦。
鲁本

2
我认为这不是一个很好的解决方案,因为需要提供当前文件的名称。如果文件被重命名怎么办?它不再起作用了。此外,当程序在RStudio中运行时,它不起作用。
Lance E Sloan先生

40

这对我有用:

getSrcDirectory(function(x) {x})

这将在脚本中定义一个匿名函数(不执行任何操作),然后确定该函数的源目录,即脚本所在的目录。


34
在Linux R 3.2.4上,这对我不起作用。输出为空白。
biocyberman

3
在3.3.2中为我工作。@biocyberman:您是从控制台调用此电话吗?因为它在那里确实为我返回了空白。如果是从脚本开始的,则要打印吗?(类似地,它在从Rstudio中获取源代码时会起作用,而在运行代码时则不会起作用)。
naught101 '17

1
仅当在RStudio中购买脚本时,才能在OSX 10.11.6 BUT上的3.3.2中工作,如@ naught101所写。在控制台中调用或在脚本窗口中CMD-返回行时,返回空白。
mattek

2
警告:如果在采购文件后工作目录发生了更改并且旧的工作目录包含了该文件,则此方法不起作用。原因是在这种情况下,返回的路径为“。” (即工作目录),如果工作目录更改,则不再适用。
cno

1
我尝试了很多方法来解决这个简单问题(我在Windows 10 R 3.4.1上,使用Rstudio)。从sys.frame(1)$ ofile,parent.frame(2)$ ofile等开始。我认为此答案到目前为止效果最好。
上瘾

32

仅适用于RStudio:

setwd(dirname(rstudioapi::getActiveDocumentContext()$path))

这在运行文件或为文件提供时起作用。


1
没有为我工作。我必须使用:setwd(dirname(rstudioapi :: callFun(“ getActiveDocumentContext”)$ path))否则:很好的解决方案-谢谢
MarkusN

1
在loadNamespace(名)错误:没有包称为“rstudioapi”
希拉里·桑德斯

2
@HillarySanders你install.packages("rstudioapi")呢?
Richie Cotton

使用'source'时此方法不起作用,因为它仅返回光标所在文档的路径。
安德鲁

8

利用Rscript的隐式“ --file”参数

使用“ Rscript”(Rscript doc)调用脚本时,脚本的完整路径作为系统参数给出。以下函数利用它来提取脚​​本目录:

getScriptPath <- function(){
    cmd.args <- commandArgs()
    m <- regexpr("(?<=^--file=).+", cmd.args, perl=TRUE)
    script.dir <- dirname(regmatches(cmd.args, m))
    if(length(script.dir) == 0) stop("can't determine script dir: please call the script with Rscript")
    if(length(script.dir) > 1) stop("can't determine script dir: more than one '--file' argument detected")
    return(script.dir)
}

1
当我运行它(在R 3.2.3的Ubuntu 15.10上)时,该参数--file不包含完整路径,因此返回的脚本目录为空:```daniel @ computer:〜/ data $ Rscript Script.R / usr / lib / R / bin / exec / R --slave --no-restore --file = Script.R```–
丹尼尔

为我工作(win7,R3.4)。
mdag02

6

如果将代码包装在包中,则始终可以查询包目录的一部分。
这是RGtk2包中的示例:

> system.file("ui", "demo.ui", package="RGtk2")
[1] "C:/opt/R/library/RGtk2/ui/demo.ui"
> 

您可以对inst/glade/源代码中的目录执行相同操作,该目录将成为glade/已安装软件包中的目录-并system.file()在安装时为您计算路径,而与操作系统无关。


谢谢德克。我真的必须开始考虑将脚本放入程序包中...我想从您的答案中可以找到在程序包之外执行此操作的方法吗?
nico

1
您可以进行其他操作-设置环境变量并进行查询,或者将提供脚本名称的参数解析为R,或者...但是为什么不为此目的使用简单,经过测试,可靠的方法呢?;-)
Dirk Eddelbuettel 2010年

哦,当然,我只是想知道是否还有其他解决方案!谢谢!
nico 2010年

4

这个答案对我来说很好:

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

注意:必须提供脚本才能返回正确的路径

我在以下位置找到了它:https : //support.rstudio.com/hc/communities/public/questions/200895567-can-user-obtain-the-path-of-current-Project-s-directory-

但是我仍然不明白什么是sys.frame(1)$ ofile。我没有在R Documentation中找到任何有关此的信息。有人可以解释吗?


是。没有源代码,将出现以下错误:dirname(parent.frame(2)$ ofile)中的错误:预期为字符向量参数
patapouf_ai 2015年

我知道这个答案太老了,但这就是为什么它有时会起作用的原因。sys.frame(1)将返回堆栈上的第一个环境。堆栈是一个列表,允许R跟踪哪些功能在何处领先。因此,如果在R Console中运行命令'source(..)',它将在堆栈中放置三项,则将source(..)作为调用堆栈中的第一项,则将'源”作为函数堆栈上的第一个,它会将环境评估为“源(..)”作为框架堆栈上的第一个。
安德鲁

'$ ofile'从'sys.frame'返回的环境中获取参数'ofile',该环境应该是'source'中使用的文件名。请注意,这只会获取第一个“源”调用的文件名,因此,如果您有多个源调用,则可能无法使用。
安德鲁

2
#' current script dir
#' @param
#' @return
#' @examples
#' works with source() or in RStudio Run selection
#' @export
z.csd <- function() {
    # http://stackoverflow.com/questions/1815606/rscript-determine-path-of-the-executing-script
    # must work with source()
    if (!is.null(res <- .thisfile_source())) res
    else if (!is.null(res <- .thisfile_rscript())) dirname(res)
    # http://stackoverflow.com/a/35842176/2292993  
    # RStudio only, can work without source()
    else dirname(rstudioapi::getActiveDocumentContext()$path)
}
# Helper functions
.thisfile_source <- function() {
    for (i in -(1:sys.nframe())) {
        if (identical(sys.function(i), base::source))
            return (normalizePath(sys.frame(i)$ofile))
    }

    NULL
}
.thisfile_rscript <- function() {
    cmdArgs <- commandArgs(trailingOnly = FALSE)
    cmdArgsTrailing <- commandArgs(trailingOnly = TRUE)
    cmdArgs <- cmdArgs[seq.int(from=1, length.out=length(cmdArgs) - length(cmdArgsTrailing))]
    res <- gsub("^(?:--file=(.*)|.*)$", "\\1", cmdArgs)

    # If multiple --file arguments are given, R uses the last one
    res <- tail(res[res != ""], 1)
    if (length(res) > 0)
        return (res)

    NULL
}

1

这些解决方案中有很多已经使用了几年。尽管有些仍然可以使用,但是有充分的理由反对使用它们中的每一个(请参阅下面的链接源)。我有最好的解决方案(也来自源代码):使用here库。

原始示例代码:

library(ggplot2)
setwd("/Users/jenny/cuddly_broccoli/verbose_funicular/foofy/data")
df <- read.delim("raw_foofy_data.csv")

修改后的代码

library(ggplot2)
library(here)

df <- read.delim(here("data", "raw_foofy_data.csv"))

该解决方案是最动态,最健壮的,因为它不管您是否使用命令行,RStudio,从R脚本进行调用等都可以使用。它使用起来也非常简单且简洁。

资料来源:https : //www.tidyverse.org/articles/2017/12/workflow-vs-script/


1
这不能回答问题。
WDS

仅当您将R脚本组织到R和RStudio项目中时,此方法才有效。如果不是,则库“ here”仅获取当前的工作目录,绝对不是您想要的目录。
安德鲁

0

如何使用系统和外壳命令?对于Windows,我想当您在RStudio中打开脚本时,会将当前的shell目录设置为脚本的目录。您可能需要添加cd C:\或任何要搜索的驱动器(例如shell('dir C:\\ * file_name / s',intern = TRUE)-\\以转义转义字符)。除非您进一步指定子目录(对于Linux,我从/开始搜索),否则它仅适用于唯一命名的文件。无论如何,如果您知道如何在Shell中查找内容,这将提供一种布局以在R中找到它并返回目录。无论您是采购还是运行脚本,都应该可以工作,但是我还没有完全探究潜在的错误。

#Get operating system
OS<-Sys.info()
win<-length(grep("Windows",OS))
lin<-length(grep("Linux",OS))

#Find path of data directory
#Linux Bash Commands
if(lin==1){
  file_path<-system("find / -name 'file_name'", intern = TRUE)
  data_directory<-gsub('/file_name',"",file_path)
}
#Windows Command Prompt Commands
if(win==1){
  file_path<-shell('dir file_name /s', intern = TRUE)
  file_path<-file_path[4]
  file_path<-gsub(" Directory of ","",file_path)
  filepath<-gsub("\\\\","/",file_path)
  data_directory<-file_path
}

#Change working directory to location of data and sources  
setwd(data_directory)

0

谢谢您的功能,尽管我必须对它进行如下调整(W10):

#Windows Command Prompt Commands
if(win==1){
  file_path<-shell('dir file_name', intern = TRUE)
  file_path<-file_path[4]
  file_path<-gsub(" Verzeichnis von ","",file_path)
  file_path<-chartr("\\","/",file_path)
  data_directory<-file_path
}

0

我知道这个问题现在已经很老了,但是我想回答,因为我制作了一个软件包来处理这个问题。它称为“ this.path”,可在CRAN上使用,因此可以像使用以下任何其他软件包一样安装:install.packages(“ this.path”)

从RStudio,RGui,命令行//终端(Rscript)运行R以及使用'source'时,它应检索执行脚本的文件名。


0

就我而言,我需要一种复制执行文件的方法来备份原始脚本及其输出。这在研究中相对重要。在命令行上运行脚本时,对我有用的是这里介绍的其他解决方案的混合,如下所示:

library(scriptName)
file_dir <- gsub("\\", "/", fileSnapshot()$path, fixed=TRUE)
file.copy(from = file.path(file_dir, scriptName::current_filename()) ,
          to = file.path(new_dir, scriptName::current_filename()))

或者,可以在文件名中添加日期和我们的名称,以帮助将文件与源文件区分开,如下所示:

file.copy(from = file.path(current_dir, current_filename()) ,
          to = file.path(new_dir, subDir, paste0(current_filename(),"_", Sys.time(), ".R")))

1
阅读您的阅读3次后,我仍然不知道如何解决该问题。OP并未询问如何复制文件。您可以将答案缩小到相关部分吗,又比其他解决方案好得多?谢谢
StupidWolf

@StupidWolf该功能scriptName::current_filename()是唯一可以在没有Rstudio且没有提供要复制文件的Linux服务器上检索文件名的功能,因为此处的大多数解决方案都sys.frame(1)$ofile需要您执行此操作。获得所需的文件名后,您只需找到当前的脚本目录,并通过fileSnapshot()$path进行一些其他调整即可解决该问题gsub。希望对您有所帮助。
马科斯

@Marcos首先,第二行不需要'paste0'。其次,fileSnapshot()返回有关当前工作目录的信息,而不是有关执行脚本目录的信息。第三,在Windows上不需要用反斜杠替换反斜杠,这是可以接受的,但是在Unix上是危险的。您的答案中与该问题有关的部分仅是'scriptName :: current_filename'部分,其余部分可能会被修整。
安德鲁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.