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

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

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

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


当前回答

我对上面的实现有问题,因为我的脚本是从符号链接目录操作的,或者至少这就是为什么我认为上面的解决方案不适合我。按照@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的方法是有效的,但前提是路径中没有空白。在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块。

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

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

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

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

我希望这能有所帮助。

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

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

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