Rscript:确定执行脚本的路径

时间:2009-11-29 13:58:33

标签: r file path rscript r-faq

我有一个名为foo.R的脚本,其中包含另一个脚本other.R,该脚本位于同一目录中:

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

但我希望R找到other.R,无论当前的工作目录是什么。

换句话说,foo.R需要知道自己的路径。我怎么能这样做?

29 个答案:

答案 0 :(得分:87)

Here这个问题有一个简单的解决方案。这个命令:

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

返回当前脚本文件的路径。保存脚本后,它可以正常工作。

答案 1 :(得分:62)

您可以使用commandArgs函数获取Rscript传递给实际R解释器的所有选项,并搜索--file=。如果您的脚本是从路径启动的,或者是使用完整路径启动的,则下面的script.name将以'/'开头。否则,它必须相对于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)

other.R

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"

这就是我认为德曼正在寻找的东西。

答案 2 :(得分:49)

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

答案 3 :(得分: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)]])

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

答案 4 :(得分:22)

来自rakensiGetting path of an R script的答案是最正确且非常出色的恕我直言。然而,它仍然是一个包含虚拟功能的黑客。我在这里引用它,以便让别人更容易找到它。

  

sourceDir&lt; - getSrcDirectory(function(dummy){dummy})

这给出了放置语句的文件的目录(定义了伪函数的位置)。然后可以使用它来设置工作目标并使用相对路径,例如

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

或创建绝对路径

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

答案 5 :(得分:21)

这对我有用

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

答案 6 :(得分:12)

Supressingfire的答案的缩小版本:

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

答案 7 :(得分:11)

我的一体! ( - 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)
                }
            }
        }
    }
}

答案 8 :(得分:10)

这对我有用。只需从命令行参数中获取它,剥离不需要的文本,执行一个dirname,最后从中获取完整路径:

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

答案 9 :(得分:6)

我已将这个问题的答案整理成rprojroot中的新函数thisfile()。也适用于knitr编织。

答案 10 :(得分:6)

我从这个问题Getting path of an R scriptGet the path of current scriptFind location of current .R fileR command for setting working directory to source file location in Rstudio中尝试了几乎所有方法,但最后发现自己手动浏览了CRAN表并找到了

scriptName

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

答案 11 :(得分: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))
        }
    }
}

答案 12 :(得分:5)

我自己就是这样做的。为确保脚本的可移植性始终以:

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

它起作用是因为“。”像Unix命令$ PWD一样翻译。将此字符串分配给字符对象允许您将该字符对象插入到setwd()和 Presto 中,您的代码将始终以其当前目录作为工作目录运行,无论它在哪台机器上或它所在的文件结构中的位置。 (额外的好处:wd对象可以与file.path()一起使用(即file.path(wd,“output_directory”),以允许创建标准输出目录,而不管通往命名目录的文件路径如何。这确实需要您在以这种方式引用之前创建新目录,但这也可以使用wd对象进行帮助。

或者,以下代码执行完全相同的操作:

wd <- getwd()
setwd(wd)

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

setwd(".")

答案 13 :(得分:2)

从2020年12月3日起,我已经在CRAN上提供了名为“ this.path”的软件包。

使用以下方法安装:

install.packages(“ this.path”)

,然后通过以下方式使用它:

this.path :: this.path()

库(this.path)

this.path()

尽管它的功能比软件包中的版本要少,但我仍然有下面的原始答案。在类似Unix的OS上,将替换'Rscript'命令行参数'file'中的奇怪字符(例如“”)(例如“〜+〜”)。 R这样做是为了更轻松地将该文件名用于其他系统命令,但这不是我们想要的。鉴于我们想要在R中可用的路径,因此必须替换任何此类奇怪的字符序列。

原始答案:

我的答案是对杰里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 and formal argument \"--file=\" matched by multiple actual arguments\n")
        }
        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 and argument \"--file=\" is missing\n")
    }
    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\n")
        }


        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\n")
        }
        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\n")
    }
    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("this error SHOULD be unreachable, as far as I know it's impossible to have an R\n",
                "  process running without the R Console open. If you reached this error, please\n",
                "  send a bug report to the package maintainer")


        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\n")
        }


        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\n")
        }
        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\n")
    }
    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\n")
    }
    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\n")
}

答案 14 :(得分:2)

我喜欢这种方法:

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

答案 15 :(得分:2)

请注意,getopt包提供get_Rscript_filename函数,它只使用此处提供的相同解决方案,但已在标准R模块中为您编写,因此您无需复制和粘贴“获取脚本路径“函数到您编写的每个脚本中。

答案 16 :(得分:2)

您可以将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

答案 17 :(得分:1)

您可能只使用99%的案例:

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

对于脚本不是第一个参数的疯狂调用,它不起作用,即source(some args, file="myscript")。在这些奇特的案例中使用@ hadley。

答案 18 :(得分:1)

我会使用@ steamer25方法的变体。关键是我更喜欢获取最后一个源脚本,即使我的会话是通过Rscript启动的。以下代码段包含在文件中时,将提供包含脚本规范化路径的变量thisScript。 我承认(ab)使用了源代码,所以有时我会调用Rscript并且--file参数中提供的脚本会从另一个脚本中获取另一个脚本...有一天我会投入使我的混乱代码变成包裹。

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

答案 19 :(得分:1)

我遇到上述实现的问题,因为我的脚本是从符号链接目录操作的,或者至少我认为上述解决方案对我不起作用的原因。按照@ 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)

答案 20 :(得分:1)

请参阅R.utils包的findSourceTraceback()

  

查找所有&#39; srcfile&#39;在所有调用帧中由source()生成的对象。   这样就可以找出当前由source()编写的文件。

答案 21 :(得分:0)

Steamer25的方法有效,但前提是路径中没有空格。在macOS上,至少cmdArgs[match]会为/base/some~+~dir~+~with~+~whitespace/返回/base/some\ dir\ with\ whitespace/之类的内容。

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

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块。

答案 22 :(得分:0)

如果不是脚本,foo.R,知道其路径位置,如果您可以将代码更改为始终引用来自公共source的所有root'd路径,那么这些可能是一个很大的帮助:

给出

  • /app/deeply/nested/foo.R
  • /app/other.R

这将有效

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

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

答案 23 :(得分:0)

令人惊讶的是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)

然后只拆分其他.R

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

答案 24 :(得分:0)

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

答案 25 :(得分:0)

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

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

答案 26 :(得分:0)

我也遇到了这个问题,上面的解决方案都不适合我。也许使用source之类的东西,但还不够清楚。

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

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

其中最重要的是fileSnapshot(),可为您提供有关文件的大量信息。它返回8个元素的列表。当您选择path作为列表元素时,将以\\作为分隔符返回路径,因此其余代码仅是对其进行更改。

我希望这会有所帮助。

答案 27 :(得分:0)

我在HPC集群环境中工作。我在生产运行所在的其他位置开发代码。在开发期间,我通常是从命令行(使用RStudio而不是 )以交互方式调用R。有很多source("foo.R")正在进行。

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

other.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/to/R/code中运行此代码,只需执行

> source("foo.R")

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

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

答案 28 :(得分:0)

解决方案于 2016 年推出。非常感谢作者 Sahil Seth!

CRANgithub 上的包 funr 提供了函数 sys.script(),它获取当前脚本的完整路径。它甚至引用了类似的 SO post

因此,解决方案是:

myscript.R:

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

然后执行命令:

user@somewhere:/home$ Rscript myscript.R

在命令行会输出,例如:

"/home/path/to/myscript.R"

到控制台。