查找当前.R文件的位置

27
我已经查看了许多类似的问题(请参见文章末尾),但我没有找到任何可以实现我所需功能的解决方案。根据项目不同,我会在Windows或Fedora上编写代码,并为使用Windows和几个Linux发行版的人编写代码。
我的工作之一是为人们制作R脚本,以自动分析数据并创建图表。最常见的情况是,我只需将脚本发送给他们,然后它就会生成图表。这样,如果数据发生变化或扩展,我就不需要重新运行脚本(此外,他们可以根据需要进行更改)。
问题是,我不知道如何让R脚本找到自己的位置。能够创建以下代码非常方便:
  1. 用户将脚本保存到包含数据的文件夹中,然后运行脚本。
    • 通常我只是通过电子邮件将脚本发送给我的合作伙伴。
    • 他们将脚本保存到包含要分析/绘图的数据的文件夹中。
    • 理想情况下,他们只需启动R,加载脚本,然后运行脚本。
  2. 脚本确定自己的位置,然后将其设置为工作目录。
  3. 脚本分析其所在目录中的数据。
  4. 脚本生成图形并将其保存到其所在目录中。

这个问题只涉及步骤2。只要我能完成这一步,其他一切都很顺利。最好有这样的东西:

setwd(FindThisScriptsLocation())

有人建议使用source(..., chdir = T)这行代码来解决问题(这里),但是它无法用于脚本引用自身,除非知道它自己的路径。

以下是一些相关问题:


2
请提供类似问题的链接,并告诉我们在这种情况下具体哪些方面不起作用。 - Joshua Ulrich
4
第一步中,用户是如何运行脚本的?这决定了如何将该信息传递给函数。 - Ricardo Saporta
1
@HongOoi 我的同事们明确表示他们希望我来做这件事。目前,每次更改工作目录或位置时,我们都必须手动设置它。 - Will Beason
1
这似乎过于复杂了。为什么不直接发送一个工作区文件(通过 save.image 创建),其中包含他们可以调用的函数呢?只要 .RData 文件与 R 相关联,他们就可以在保存到任何目录后双击该文件,然后调用该函数。 - Joshua Ulrich
显示剩余8条评论
5个回答

14

我也遇到了同样的问题,这是我想出的解决方法。它可以在Windows和Linux上使用source()和rmarkdwon::render()。

更新:函数get_scriptpath()现在作为我的envDocument软件包的一部分可在CRAN上获得。请参见https://cran.r-project.org/package=envDocument

#' Get the path of the calling script
#' 
#' \code{get_scriptpath} returns the full path of the script that called this function (if any)
#' or NULL if path is not available
#' 
#' @examples 
#' mypath <- get_scriptpath()
#' @export
#' 
get_scriptpath <- function() {
  # location of script can depend on how it was invoked:
  # source() and knit() put it in sys.calls()
  path <- NULL

  if(!is.null(sys.calls())) {
    # get name of script - hope this is consisitent!
    path <- as.character(sys.call(1))[2] 
    # make sure we got a file that ends in .R, .Rmd or .Rnw
    if (grepl("..+\\.[R|Rmd|Rnw]", path, perl=TRUE, ignore.case = TRUE) )  {
      return(path)
    } else { 
      message("Obtained value for path does not end with .R, .Rmd or .Rnw: ", path)
    }
  } else{
    # Rscript and R -f put it in commandArgs
    args <- commandArgs(trailingOnly = FALSE)
  }
  return(path)
}

1
我对如何使用这个函数感到困惑...我应该传递什么参数?当不传递参数调用 get_scriptpath() 时,我会收到以下错误消息:Error in get_scriptpath() : No path information available - Asy
1
此函数不带参数。仅当从正在运行的脚本中调用时才能正常工作(例如,如果您使用Rscript、source或rmarkdown::render运行脚本或RMD文件)。如果您从R控制台调用它,它将无法工作,因为控制台不是脚本。https://cran.r-project.org/package=envDocument 上的 envDocument 包提供了一个带有改进文档和错误处理的此函数版本。 - DonJ
为什么要按文件扩展名进行过滤?您遇到过没有预期扩展名之一的调用文件的情况吗? - bokov
1
偏执狂——如果由于某种原因运行脚本/报告的系统调用不在我期望的位置,那么我希望能提前得到通知;我相信它将始终位于sys.call返回值中的相同位置。回想起来,我甚至可能会将其升级为警告或错误。而且,我不想想象如果有一个具有预期扩展名的不正确值的情况... - DonJ
同意 - 这个的重点是在脚本或rmarkdown::rendr中记录调用。对于从控制台使用,没有“脚本”这个概念,因此不适用。 - DonJ
显示剩余2条评论

5

在“加载脚本”的过程中,您需要传递R脚本的名称和路径。我建议捕获这些信息,然后使用包装脚本来执行您的主要脚本。

选项1(通过编程)

这个包装函数将以需要执行的脚本的路径和文件名为参数。

FILE <- "~/Desktop/myFolder/InHere/myScript.R"

选项2(交互式)

在您的包装函数开头,让用户点击文件:

FILE <- file.choose()

然后:

DIR  <- dirname(FILE)

现在您已经拥有了您的目录/文件夹,您可以像平常一样传递DIR参数来执行您的脚本。


3

嘿,我有一个可能的解决方案,需要一些额外的初始工作,但应该能够做到你需要的。

首先让你的R脚本接受一个参数,这个参数是脚本的位置。接下来,你只需要创建一个Bash/Batch(分别为Windows和Unix):

1)获取它自己的目录

2)在目录中搜索一个R脚本(简单的*.R搜索)

3)使用步骤1中的目录调用R脚本。

然后,你只需将Bash和Batch脚本与你提供给客户的文件夹一起打包,并要求他们仅运行其环境下相关的脚本。

理论上,你只需要创建一次Bash/Batch脚本。

编辑:我已经创建了一个简单的Bash脚本来解决这个问题,请见下文。

#!/bin/bash

#Modify the search string to narrow the search
SEARCH_STRING="*.R"

#Get the current directory
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo ${DIR}

#Get the name of the R script
R_SCRIPT=`find $DIR -name ${SEARCH_STRING} -type f -exec basename {} \;`
echo ${R_SCRIPT}

Rscript ${R_SCRIPT} ${DIR}

由于我对Windows Shell不是很熟悉,所以你需要自己完成这个任务 :P

你可以使用这个R脚本进行测试;

options(echo = FALSE) #So we don't get the script echo'd

arguments <- commandArgs(trailingOnly = TRUE) #getting the arguments

working_directory <- arguments[1]

setwd(working_directory)

getwd() #print out to test

1
我假设这是Windows。
根据Ricardo的建议:让客户端系统以这种方式设置,即如果双击脚本,则在脚本目录中启动R解释器。您还可以为此行为分配一个特殊扩展名(例如,用于“设置工作目录的R脚本”的.Rwd)。然后,您不需要在脚本内使用setwd()
首先,以下命令行脚本可能会起作用(未经测试):
pushd %~d1%~p1
R --vanilla < "%1"

.Rwd 文件与此脚本关联。

如果您需要 source() 其他脚本,请考虑使用 chdir=T 参数。


我主要使用Windows,但根据项目需要也会使用Fedora。我为那些运行Windows和一些Linux发行版的人编写代码。你的答案肯定可行(我会学习如何做你所说的,听起来非常有用),但并不完全理想。 - Will Beason
4
可以将 %~d1%~p1 缩写为 %~dp1 - Matthew Lundberg

-2
如果您正在使用RStudio,请将光标悬停在脚本上,路径将会出现。

enter image description here


@stevec- 这个问题涉及批处理执行,而不是使用Rstudio GUI。 - DonJ
@DonJ 可能是对的,但我是在搜索如何在RStudio中查看R文件的位置时到达这里的,所以我猜其他人也会从同样的谷歌搜索中到达这里。因此,在这里包含这些信息是相当无害的。 - stevec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接