Rscript: Determine path of the executing script

2018-12-31 09:26发布

I have a script called foo.R that includes another script other.R, which is in the same directory:

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

But I want R to find that other.R no matter what the current working directory.

In other words, foo.R needs to know its own path. How can I do that?

24条回答
怪性笑人.
2楼-- · 2018-12-31 10:19

Amazing there is no '$0' type structure in R! You can do it with a system() call to a bash script written in R:

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

Then just split out the scriptpath.sh name for other.R

splitstr <- rev(strsplit(thisscript, "\\/")[[1]])
otherscript <- paste0(paste(rev(splitstr[2:length(splitstr)]),collapse="/"),"/other.R")
查看更多
余欢
3楼-- · 2018-12-31 10:20

I couldn't get Suppressingfire's solution to work when 'source'ing from the R console.
I couldn't get hadley's solution to work when using Rscript.

Best of both worlds?

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))
        }
}
查看更多
君临天下
4楼-- · 2018-12-31 10:24

This works for me. Just greps it out of the command line arguments, strips off the unwanted text, does a dirname and finally gets the full path from that:

args <- commandArgs(trailingOnly = F)  
scriptPath <- normalizePath(dirname(sub("^--file=", "", args[grep("^--file=", args)])))
查看更多
回忆,回不去的记忆
5楼-- · 2018-12-31 10:26

Steamer25's approach works, but only if there is no whitespace in the path. On macOS at least the cmdArgs[match] returns something like /base/some~+~dir~+~with~+~whitespace/ for /base/some\ dir\ with\ whitespace/.

I worked around this by replacing the "~+~" with a simple whitespace before returning it.

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

Obviously you can still extend the else block like aprstar did.

查看更多
余欢
6楼-- · 2018-12-31 10:27

Here there is a simple solution for the problem. This command:

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

returns the path of the current script file. It works after the script was saved.

查看更多
倾城一夜雪
7楼-- · 2018-12-31 10:27

Note that the getopt package provides the get_Rscript_filename function, which just uses the same solution presented here, but is already written for you in a standard R module, so you don't have to copy and paste the "get script path" function into every script you write.

查看更多
登录 后发表回答