71
votes

Is there a way to programmatically find the path of an R script inside the script itself?

I am asking this because I have several scripts that use RGtk2 and load a GUI from a .glade file.

In these scripts I am obliged to put a setwd("path/to/the/script") instruction at the beginning, otherwise the .glade file (which is in the same directory) will not be found.

This is fine, but if I move the script in a different directory or to another computer I have to change the path. I know, it's not a big deal, but it would be nice to have something like:

setwd(getScriptPath())

So, does a similar function exist?

12
This would be particularly useful in interactive sessions, such as when using Rstudio.Quantum7
It seems that many of these "path to file" problems may now be solved with the package rprojroot: cran.r-project.org/web/packages/rprojroot/index.html . rprojroot bills itself as "rprojroot: Finding Files in Project Subdirectories." A 'lightweight' version for interactive use is the here package: github.com/krlmlr/here .BarkleyBG
The solution provided by @BarkleyBG (the here package) worked very well for me.MauOlivares

12 Answers

26
votes

Use source("yourfile.R", chdir = T)

41
votes

This works for me:

getSrcDirectory(function(x) {x})

This defines an anonymous function (that does nothing) inside the script, and then determines the source directory of that function, which is the directory where the script is.

35
votes

For RStudio only:

setwd(dirname(rstudioapi::getActiveDocumentContext()$path))

This works when Running or Sourceing your file.

8
votes

Exploit the implicit "--file" argument of Rscript

When calling the script using "Rscript" (Rscript doc) the full path of the script is given as a system parameter. The following function exploits this to extract the script directory:

getScriptPath <- function(){
    cmd.args <- commandArgs()
    m <- regexpr("(?<=^--file=).+", cmd.args, perl=TRUE)
    script.dir <- dirname(regmatches(cmd.args, m))
    if(length(script.dir) == 0) stop("can't determine script dir: please call the script with Rscript")
    if(length(script.dir) > 1) stop("can't determine script dir: more than one '--file' argument detected")
    return(script.dir)
}
7
votes

If you wrap your code in a package, you can always query parts of the package directory.
Here is an example from the RGtk2 package:

> system.file("ui", "demo.ui", package="RGtk2")
[1] "C:/opt/R/library/RGtk2/ui/demo.ui"
> 

You can do the same with a directory inst/glade/ in your sources which will become a directory glade/ in the installed package -- and system.file() will compute the path for you when installed, irrespective of the OS.

4
votes

This answer works fine to me:

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

Note: script must be sourced in order to return correct path

I found it in: https://support.rstudio.com/hc/communities/public/questions/200895567-can-user-obtain-the-path-of-current-Project-s-directory-

But I still don´t understand what is sys.frame(1)$ofile. I didn´t find anything about that in R Documentation. Someone can explain it?

2
votes
#' current script dir
#' @param
#' @return
#' @examples
#' works with source() or in RStudio Run selection
#' @export
z.csd <- function() {
    # http://stackoverflow.com/questions/1815606/rscript-determine-path-of-the-executing-script
    # must work with source()
    if (!is.null(res <- .thisfile_source())) res
    else if (!is.null(res <- .thisfile_rscript())) dirname(res)
    # http://stackoverflow.com/a/35842176/2292993  
    # RStudio only, can work without source()
    else dirname(rstudioapi::getActiveDocumentContext()$path)
}
# Helper functions
.thisfile_source <- function() {
    for (i in -(1:sys.nframe())) {
        if (identical(sys.function(i), base::source))
            return (normalizePath(sys.frame(i)$ofile))
    }

    NULL
}
.thisfile_rscript <- function() {
    cmdArgs <- commandArgs(trailingOnly = FALSE)
    cmdArgsTrailing <- commandArgs(trailingOnly = TRUE)
    cmdArgs <- cmdArgs[seq.int(from=1, length.out=length(cmdArgs) - length(cmdArgsTrailing))]
    res <- gsub("^(?:--file=(.*)|.*)$", "\\1", cmdArgs)

    # If multiple --file arguments are given, R uses the last one
    res <- tail(res[res != ""], 1)
    if (length(res) > 0)
        return (res)

    NULL
}
1
votes

A lot of these solutions are several years old. While some may still work, there are good reasons against utilizing each of them (see linked source below). I have the best solution (also from source): use the here library.

Original example code:

library(ggplot2)
setwd("/Users/jenny/cuddly_broccoli/verbose_funicular/foofy/data")
df <- read.delim("raw_foofy_data.csv")

Revised code

library(ggplot2)
library(here)

df <- read.delim(here("data", "raw_foofy_data.csv"))

This solution is the most dynamic and robust because it works regardless of whether you are using the command line, RStudio, calling from an R script, etc. It is also extremely simple to use and is succinct.

Source: https://www.tidyverse.org/articles/2017/12/workflow-vs-script/

0
votes

How about using system and shell commands? With the windows one, I think when you open the script in RStudio it sets the current shell directory to the directory of the script. You might have to add cd C:\ e.g or whatever drive you want to search (e.g. shell('dir C:\\*file_name /s', intern = TRUE) - \\ to escape escape character). Will only work for uniquely named files unless you further specify subdirectories (for Linux I started searching from /). In any case, if you know how to find something in the shell, this provides a layout to find it within R and return the directory. Should work whether you are sourcing or running the script but I haven't fully explored the potential bugs.

#Get operating system
OS<-Sys.info()
win<-length(grep("Windows",OS))
lin<-length(grep("Linux",OS))

#Find path of data directory
#Linux Bash Commands
if(lin==1){
  file_path<-system("find / -name 'file_name'", intern = TRUE)
  data_directory<-gsub('/file_name',"",file_path)
}
#Windows Command Prompt Commands
if(win==1){
  file_path<-shell('dir file_name /s', intern = TRUE)
  file_path<-file_path[4]
  file_path<-gsub(" Directory of ","",file_path)
  filepath<-gsub("\\\\","/",file_path)
  data_directory<-file_path
}

#Change working directory to location of data and sources  
setwd(data_directory)
0
votes

Thank you for the function, though I had to adjust it a Little as following for me (W10):

#Windows Command Prompt Commands
if(win==1){
  file_path<-shell('dir file_name', intern = TRUE)
  file_path<-file_path[4]
  file_path<-gsub(" Verzeichnis von ","",file_path)
  file_path<-chartr("\\","/",file_path)
  data_directory<-file_path
}
0
votes

I know this question is old at this point, but I'd like to answer because I made a package to handle this problem. It's called "this.path" and it's available on CRAN so it can be installed like any other package using: install.packages("this.path")

It should retrieve the executing script's filename when running R from RStudio, RGui, the command-line / / terminal (Rscript), and when using 'source'.

0
votes

In my case, I needed a way to copy the executing file to back up the original script together with its outputs. This is relatively important in research. What worked for me while running my script on the command line, was a mixure of other solutions presented here, that looks like this:

library(scriptName)
file_dir <- gsub("\\", "/", fileSnapshot()$path, fixed=TRUE)
file.copy(from = file.path(file_dir, scriptName::current_filename()) ,
          to = file.path(new_dir, scriptName::current_filename()))

Alternatively, one can add to the file name the date and our to help in distinguishing that file from the source like this:

file.copy(from = file.path(current_dir, current_filename()) ,
          to = file.path(new_dir, subDir, paste0(current_filename(),"_", Sys.time(), ".R")))