我有一个名为foo的脚本。R包含另一个脚本other。R,在同一个目录下:

#!/usr/bin/env Rscript
message("Hello")
source("other.R")

但我想让R找到另一个。R,不管当前工作目录是什么。

换句话说,就是foo。R需要知道自己的路径。我该怎么做呢?


你可以在一个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

你可以使用commandArgs函数获取Rscript传递给实际R解释器的所有选项,并搜索——file=。如果你的脚本是从路径启动的,或者它是以一个完整的路径启动的,下面的script.name将以'/'开头。否则,它必须是相对于cwd,你可以连接两个路径,以获得完整的路径。

编辑:听起来你只需要上面的script.name,并剥离路径的最后一个组件。我已经删除了不需要的cwd()样本,并清理了主脚本,并张贴了我的其他. r。只需要保存这个脚本和其他脚本。R脚本放到同一个目录下,chmod +x它们,然后运行主脚本。

主要。接待员:

#!/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)

其他。接待员:

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)]])

不要问我它是如何工作的,因为我已经忘记了:/

Supressingfire回答的简化版本:

source_local <- function(fname){
    argv <- commandArgs(trailingOnly = FALSE)
    base_dir <- dirname(substring(argv[grep("--file=", argv)], 8))
    source(paste(base_dir, fname, sep="/"))
}

这对我很有用。只是从命令行参数中greps它,去掉不需要的文本,执行dirname,最后从它获得完整的路径:

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))

当从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))
        }
}

这个问题有一个简单的解决办法。这个命令:

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

返回当前脚本文件的路径。它在保存脚本后工作。

我已经将这个问题的答案打包并扩展为rprojroot中的新函数thisfile()。也适用于编织与针织。

参见R.utils包的findSourceTraceback(),其中

查找source()在所有调用帧中生成的所有'srcfile'对象。 这使得可以找出当前由source()编写脚本的文件。

#!/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='/'))

我喜欢这种方法:

this.file <- sys.frame(tail(grep('source',sys.calls()),n=1))$ofile
this.dir <- dirname(this.file)

我对上面的实现有问题,因为我的脚本是从符号链接目录操作的,或者至少这就是为什么我认为上面的解决方案不适合我。按照@ennuikiller的回答,我将Rscript包装在bash中。我使用pwd -P设置路径变量,它解析符号链接目录结构。然后将路径传递给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的解决方案,因为它似乎是最健壮的。然而,当在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))
        }
    }
}

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))
  }
})()

在我看来,从R脚本的获取路径中得到的rakensi的答案是最正确和真正精彩的。然而,它仍然是一个包含哑函数的黑客。我在这里引用它,是为了让别人更容易发现。

sourceDir <- getSrcDirectory(函数(dummy) {dummy})

这给出了放置语句的文件的目录(在那里定义了dummy函数)。然后可以使用它来设置工作目录并使用相对路径。

setwd(sourceDir)
source("other.R")

或者创建绝对路径

 source(paste(sourceDir, "/other.R", sep=""))

我的一切都在一个!(—2019年9月1日更新以处理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)
                }
            }
        }
    }
}

我自己刚算出来的。为了确保脚本的可移植性,总是以以下开头:

wd <- setwd(".")
setwd(wd)

It works because "." translates like the Unix command $PWD. Assigning this string to a character object allows you to then insert that character object into setwd() and Presto your code will always run with its current directory as the working directory, no matter whose machine it is on or where in the file structure it is located. (Extra bonus: The wd object can be used with file.path() (ie. file.path(wd, "output_directory") to allow for the creation of a standard output directory regardless of the file path leading to your named directory. This does require you to make the new directory before referencing it this way but that, too, can be aided with the wd object.

或者,下面的代码执行完全相同的事情:

wd <- getwd()
setwd(wd)

或者,如果你不需要对象中的文件路径,你可以简单地:

setwd(".")

99%的情况你可以简单地使用:

sys.calls()[[1]] [[2]]

它将不适用于脚本不是第一个参数的疯狂调用,即source(some args, file="myscript")。在这些奇特的情况下使用@hadley's。

请注意,getopt包提供了get_Rscript_filename函数,该函数使用与本文相同的解决方案,但已经在标准R模块中为您编写了该解决方案,因此您不必将“获取脚本路径”函数复制并粘贴到您编写的每个脚本中。

Steamer25的方法是有效的,但前提是路径中没有空白。在macOS上,至少cmdArgs[match]返回类似/base/some~+~dir~+~带~+~空格/ for /base/some\ dir\带\空格/。

我通过在返回之前用一个简单的空格替换“~+~”来解决这个问题。

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那样扩展else块。

这对我很有用

library(rstudioapi)    
rstudioapi::getActiveDocumentContext()$path

如果而不是脚本,foo。R,知道它的路径位置,如果你可以改变你的代码,总是从一个公共根引用所有的源路径,那么这些可能会有很大的帮助:

https://github.com/r-lib/rprojroot或https://rprojroot.r-lib.org/ https://here.r-lib.org/

鉴于

/ app /深度/嵌套/ foo。R /应用程序/其他。R

这是可行的

#!/usr/bin/env Rscript
library(here)
source(here("other.R"))

参见https://rprojroot.r-lib.org/了解如何定义项目根。

令人惊讶的是R中没有“$0”类型结构!你可以通过system()调用一个用R编写的bash脚本来实现:

write.table(c("readlink -e $0"), file="scriptpath.sh",col=F, row=F, quote=F)
thisscript <- system("sh scriptpath.sh", intern = TRUE)

然后将scriptpath.sh名称拆分为other。R

splitstr <- rev(strsplit(thisscript, "\\/")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")

从这个问题,获取R脚本的路径,获取当前脚本的路径,查找当前。R文件的位置,以及在Rstudio中将工作目录设置为源文件位置的R命令,我几乎尝试了所有方法,但最后发现自己手动浏览CRAN表并发现

脚本名称库

它提供了current_filename()函数,该函数在RStudio中提供源代码时,以及通过R或RScript可执行文件调用时,返回脚本的正确完整路径。

通过查看调用堆栈,我们可以获得正在执行的每个脚本的文件路径,其中最有用的两个可能是当前正在执行的脚本,或者是要获取的第一个脚本(条目)。

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) ))()

我也有这个问题,上面的解决方案都不适合我。也许是来源之类的,但还不够清楚。

我找到了这个,对我来说很优雅的解决方案:

paste0(gsub("\\", "/", fileSnapshot()$path, fixed=TRUE),"/")

其中重要的是fileSnapshot(),它提供了关于文件的大量信息。它返回一个包含8个元素的列表。当您选择path作为列表元素时,路径将以\\作为分隔符返回,因此其余代码只是更改这一点。

我希望这能有所帮助。

我在一个高性能计算集群环境中工作。我在不同的地方开发代码,而不是在生产运行的地方。在开发过程中,我通常从命令行交互式地调用R(而不是使用RStudio)。有很多来源(“foo.R”)正在进行。

在生产运行期间,我通常编写一个bash脚本,尝试不同的参数,并在单独的目录中运行每一组参数。bash脚本利用了工作负载管理器(即SLURM)。在这种环境中,设置环境变量很简单。考虑到这一点,下面的解决方案最适合我。

其他。R

my_message <- function(){
return("R is awkward")
}

foo。R

srcpath = Sys.getenv("R_SRC")
# Check if runnning w/o setting R_SRC - presumably done in directory of development, i.e. /path/to/R/code
if(srcpath == ""){
    srcpath="./"
}
source(sprintf("%s/other.R", srcpath))
string = my_message()
print(string)

如果从R交互式shell中运行,并且在/path/到/R/code中运行,那么简单

> source("foo.R")

如果不是从交互式shell运行,也不是从/path/to/R/code运行,首先设置环境变量R_SRC,然后调用Rscript

$ export R_SRC=/path/to/R/code/
$ Rscript /path/to/R/code/foo.R

我为此做了一个包,在CRAN和GitHub上可用,名为“this.path”。当前版本是1.2.0,发布于2023-01-16,你可以在这里找到它:

https://CRAN.R-project.org/package=this.path

https://github.com/ArcadeAntics/this.path

从CRAN安装:

跑龙套::install.packages(“this.path”)

或从GitHub安装开发版本:

utils::install.packages(“this.path”, repos = “https://raw.githubusercontent.com/ArcadeAntics/PACKAGES”)

然后使用它:

this.path: this.path ()

or

库(this.path)

this.path ()

下面的答案是我的原始答案,仅供参考,尽管它的功能比上面可用的最新版本少了很多。改进包括:

this.path() now works within VSCode handling filenames with spaces when running an R script from a shell under Unix-alikes handling both uses of running an R script from a shell (-f file and --file=file) correctly normalizes the path when using source with argument chdir = TRUE handling of file URLs with source (that is, "file://absolute or relative path" and "file:///absolute path") better handling of a connection instead of a character string within source this.path is compatible with URLs in source, that is:

source("https://host/path/to/file")

如果这一点。如果在文件中使用了Path,它将返回“https://host/path/to/file”。这也适用于以“http://”,“ftp://”和“ftps://”开头的URL。举个例子,试试:

source("https://raw.githubusercontent.com/ArcadeAntics/this.path/main/tests/this.path_w_URLs.R")

compatibility with package testthat and knitr, particularly testthat::source_file and knitr::knit introduces function here, similar to here::here, for specifying an absolute file path, relative to the executing script's directory on Windows, in Rgui, added support for all languages listed by list.dirs(system.file(package = "translations"), full.names = FALSE, recursive = FALSE) saving the normalized path within its appropriate environment the first time this.path is called within a script, making it faster to use subsequent times within the same script and being independent of working directory. This means that setwd will no longer break this.path when using relative paths within source or when running R from a shell (as long as setwd is used AFTER the first call to this.path within that script)

最初的回答:

我的回答比Jerry T的回答好多了。我发现的问题是,他们通过检查变量ofile是否在堆栈上的第一帧中找到来猜测是否进行了源调用。这将不适用于嵌套的源调用,也不适用于来自非全局环境的源调用。另外,顺序是错误的。在检查shell参数之前,我们必须寻找源调用。以下是我的解决方案:

this.path <- function (verbose = getOption("verbose"))
{
    # loop through functions that lead here from most recent to
    # earliest looking for an appropriate source call (a call to
    # function source / / sys.source / / debugSource in RStudio)
    #
    # an appropriate source call is one in which the file argument has
    # been evaluated (forced)
    #
    # for example, this means `source(this.path())` is an inappropriate
    # source call. the argument 'file' is stored as a promise
    # containing the expression "this.path()". when the value of 'file'
    # is requested, the expression is evaluated at which time there
    # should be two functions on the calling stack 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 'file' has
    # already been evaluated, the easiest way of which is to ask if a
    # variable exists, one which is only created after the expression
    # is necessarily evaluated.
    #
    # if that variable does exist, then argument 'file' has been forced
    # and the source call is deemed appropriate. For 'source', the
    # filename we want is the variable 'ofile' from that function's
    # evaluation environment. For '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
    #
    # 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 promise). 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


    debugSource <- if (.Platform$GUI == "RStudio")
        get("debugSource", "tools:rstudio", inherits = FALSE)
    for (n in seq.int(to = 1L, by = -1L, length.out = sys.nframe() - 1L)) {
        if (identical(sys.function(n), 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
            if (verbose)
                cat("Source: call to function source\n")
            return(normalizePath(path, mustWork = TRUE))
        }
        else if (identical(sys.function(n), sys.source) &&
                 exists("exprs", envir = sys.frame(n), inherits = FALSE))
        {
            path <- get("file", envir = sys.frame(n), inherits = FALSE)
            if (verbose)
                cat("Source: call to function sys.source\n")
            return(normalizePath(path, mustWork = TRUE))
        }
        else if (identical(sys.function(n), debugSource) &&
                 tryCatch({
                     path <- get("fileName", envir = sys.frame(n), inherits = FALSE)
                     TRUE
                 }, error = function(c) FALSE))
        {
            if (verbose)
                cat("Source: call to function debugSource in RStudio\n")
            return(normalizePath(path, mustWork = TRUE))
        }
    }


    # no appropriate source call was found up the calling stack


    # if (running R from RStudio)
    if (.Platform$GUI == "RStudio") {


        # ".rs.api.getActiveDocumentContext" from "tools:rstudio"
        # returns a list of information about the document where your
        # cursor is located
        #
        # ".rs.api.getSourceEditorContext" from "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


        context <- get(".rs.api.getActiveDocumentContext",
            "tools:rstudio", inherits = FALSE)()
        active <- context[["id"]] != "#console"
        if (!active) {
            context <- get(".rs.api.getSourceEditorContext",
                "tools:rstudio", inherits = FALSE)()
            if (is.null(context))
                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\n",
                     "  (or source document has no path)")
        }


        path <- context[["path"]]
        Encoding(path) <- "UTF-8"
        if (nzchar(path)) {
            if (verbose)
                cat(if (active)
                    "Source: active document in RStudio\n"
                else "Source: source document in RStudio\n")
            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",
                  if (active)
                      "* active document in RStudio does not exist"
                  else "* source document in RStudio does not exist")
    }


    # if (running R from RStudio before .Platform$GUI is changed)
    # this includes code evaluated in the site-wide startup profile file,
    # user profile, and function .First (see ?Startup) 
    else if (isTRUE(Sys.getpid() == as.integer(Sys.getenv("RSTUDIO_SESSION_PID"))) {
        stop("RStudio has not finished loading")
    }


    # if (running R from a shell)
    else if (.Platform$OS.type == "windows" && .Platform$GUI == "RTerm" ||  # on Windows
             .Platform$OS.type == "unix"    && .Platform$GUI == "X11")      # under Unix-alikes
    {


        argv <- commandArgs()
        # remove all trailing arguments
        m <- match("--args", argv, 0L)
        if (m)
            argv <- argv[seq_len(m)]
        argv <- argv[-1L]


        # get all arguments starting with "--file="
        FILE <- argv[startsWith(argv, "--file=")]
        # remove "--file=" from the start of each string
        FILE <- substring(FILE, 8L)
        # remove strings "-"
        FILE <- FILE[FILE != "-"]
        n <- length(FILE)
        if (n) {
            FILE <- FILE[[n]]
            if (verbose)
                cat("Source: shell argument 'FILE'\n")
            return(normalizePath(FILE, mustWork = TRUE))
        } 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 a shell where argument 'FILE' is missing")
        }
    }


    # if (running R from RGui on Windows)
    else if (.Platform$OS.type == "windows" && .Platform$GUI == "Rgui") {


        # "getWindowsHandles" from "utils" (Windows exclusive) returns
        # a list of external pointers containing the windows handles.
        # The thing of interest are the names of this list, these are
        # 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 start with "R Console" or end with
        # " - R Editor". From there, similar checks are done as in the
        # above section for 'RStudio'


        x <- names(utils::getWindowsHandles(pattern = "^R Console| - R Editor$",
            minimized = TRUE))


        if (!length(x))
            stop("no windows in Rgui; should never happen, please report!")


        active <- !startsWith(x[[1L]], "R Console")
        if (active)
            x <- x[[1L]]
        else if (length(x) >= 2L)
            x <- x[[2L]]
        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")
        if (x == "Untitled - R Editor")
            stop("'this.path' used in an inappropriate fashion\n",
                 "* no appropriate source call was found up the calling stack\n",
                 if (active)
                     "* active document in Rgui does not exist"
                 else "* source document in Rgui does not exist")
        path <- sub(" - R Editor$", "", x)
        if (verbose)
            cat(if (active)
                "Source: active document in Rgui\n"
            else "Source: source document in Rgui\n")
        return(normalizePath(path, mustWork = TRUE))
    }


    # if (running R from RGui on macOS)
    else if (.Platform$OS.type == "unix" && .Platform$GUI == "AQUA") {
        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 is currently unimplemented\n",
             "  consider using RStudio until such a time when this is implemented")
    }


    # otherwise
    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")
}

解决方案在2016年出现。非常感谢作者,Sahil Seth!

CRAN和github上的funr包提供了sys.script()函数,该函数获取当前脚本的完整路径。它甚至引用了一个类似的SO帖子。

因此,解是:

myscript。接待员:

#!/usr/bin/env Rscript
f  <-  funr::sys.script()
show(f)

然后执行命令:

user@somewhere:/home$ Rscript myscript.R

将在命令行输出,例如:

"/home/path/to/myscript.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')