83

I would like to set the working directory to the path of current script programmatically but first I need to get the path of current script.

So I would like to be able to do:

current_path = ...retrieve the path of current script ...
setwd(current_path) 

Just like the RStudio menu does: RStudio set working directory

So far I tried:

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)

script.name returns NULL

source("script.R", chdir = TRUE)

Returns: Error in file(filename, "r", encoding = encoding) : cannot open the connection In addition: Warning message: In file(filename, "r", encoding = encoding) : cannot open file '/script.R': No such file or directory

dirname(parent.frame(2)$ofile)

Returns: Error in dirname(parent.frame(2)$ofile) : a character vector argument expected ...because parent.frame is null

frame_files <- lapply(sys.frames(), function(x) x$ofile)
frame_files <- Filter(Negate(is.null), frame_files)
PATH <- dirname(frame_files[[length(frame_files)]])

Returns: Null because frame_files is a list of 0

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

Returns: Error in path.expand(path) : invalid 'path' argument

Also I saw all answers from here, here, here and here. No joy.

Working with RStudio 1.1.383

EDIT: It would be great if there was no need for an external library to achieve this.

5
  • 1
    Probably source("<path to file>/script.R", chdir = TRUE) will work as the help file says about chdir: * if TRUE and file is a pathname, the R working directory is temporarily changed to the directory containing file for evaluating.* The error message you get says that R can't find a file named script.R in the current working directory. Commented Oct 31, 2017 at 20:39
  • My file name is lpp.R and I do give this name... I remember in other versions of RStudio I did it easily with parent frame, now nothing Commented Oct 31, 2017 at 20:42
  • In an R studio project folder, it is a good practice to assume that all file paths are relative to the project's root directory. See Stop the working directory insanity. I personally do not use it but the here package is recommended to find where a given file is located. Commented Oct 31, 2017 at 23:01
  • @Imo -- that only works if you source the file, but not if you call it with Rscript. Commented Aug 1, 2019 at 21:07
  • 2
    @PaulRougieux -- that only works if the file you are running (or sourcing) is in the project directory. If you are running (or sourcing) a file in another location, it will not work. Commented Aug 1, 2019 at 21:08

14 Answers 14

137

In RStudio, you can get the path to the file currently shown in the source pane using

rstudioapi::getSourceEditorContext()$path

If you only want the directory, use

dirname(rstudioapi::getSourceEditorContext()$path)

If you want the name of the file that's been run by source(filename), that's a little harder. You need to look for the variable srcfile somewhere back in the stack. How far back depends on how you write things, but it's around 4 steps back: for example,

fi <- tempfile()
writeLines("f()", fi)
f <- function() print(sys.frame(-4)$srcfile)
source(fi)
fi

should print the same thing on the last two lines.

Sign up to request clarification or add additional context in comments.

17 Comments

This works great. The good thing is that it has fewer dependencies vs here package. The truth is that I was hoping to do this without a library. I will wait one/two days to check if someone has something to add and then I will accept it. Thanks.
I just did a clean install in another PC in the office. Newest R Studio (1.1.383), newest R version (R version 3.4.2 (2017-09-28)). Now I get this error: Error: 'getSourceEditorContext' is not an exported object from 'namespace:rstudioapi'
I need to make the code portable, having all data in a specific folder and make it work as fast as possible in other people pc. Specially those who just know how to press the play button and see the code producing results without any user interference
This does not run in terminal like Rscript test.R
In my case, running that snippet doesnt print the folder of the current script like the rstudioapi solution. I get "C:\\Users\\xxxx\\AppData\\Local\\Temp\\Rtmpw3wD2J\\file58d858796d29" which is not where my script is.
|
31

Update March 2019

Based on Alexis Lucattini and user2554330 answers, to make it work on both command line and RStudio. Also solving the "as_tibble" deprecated message

library(tidyverse)
getCurrentFileLocation <-  function()
{
    this_file <- commandArgs() %>% 
    tibble::enframe(name = NULL) %>%
    tidyr::separate(col=value, into=c("key", "value"), sep="=", fill='right') %>%
    dplyr::filter(key == "--file") %>%
    dplyr::pull(value)
    if (length(this_file)==0)
    {
      this_file <- rstudioapi::getSourceEditorContext()$path
    }
    return(dirname(this_file))
}

5 Comments

This actually works and should be the accepted answer in all related questions.
Nice. Within if (length ...) { }, below this_file <- ... I added if(this_file=="") message("You are running code in RStudio in a new R script window, so the filename is blank.")
Great answer ! It's also very informative of the current way of programming R, that uses tidyverse pipelines instead of loops.
From command line this causes Error: RStudio not running
I like the idea, but the code can be simplified. See my answer.
23

TLDR: The here package (available on CRAN) helps you build a path from a project's root directory. R projects configured with here() can be shared with colleagues working on different laptops or servers and paths built relative to the project's root directory will still work. The development version is at github.com/r-lib/here.

With git

You certainly store your R code in a directory. This directory is probably part of a git repository and/or an R studio project. I would recommend building all paths relative to that project's root directory. For example let's say that you have an R script that creates reusable plotting functions and that you have an R markdown notebook that loads that script and plots graphs in a nice (so nice) document. The project tree would look something like this

├── notebooks
│   ├── analysis.Rmd
├── R
│   ├── prepare_data.R
│   ├── prepare_figures.R

From the analysis.Rmd notebook, you would import plotting function with here() as such:

source(file.path(here::here("R"), "prepare_figures.R"))

Why?

Hadley Wickham in a Stackoverflow comment:

"You should never use setwd() in R code - it basically defeats the idea of using a working directory because you can no longer easily move your code between computers. – hadley Nov 20 '10 at 23:44 "

From the Ode to the here package:

Do you: Have setwd() in your scripts? PLEASE STOP DOING THAT. This makes your script very fragile, hard-wired to exactly one time and place. As soon as you rename or move directories, it breaks. Or maybe you get a new computer? Or maybe someone else needs to run your code? [...] Classic problem presentation: Awkwardness around building paths and/or setting working directory in projects with subdirectories. Especially if you use R Markdown and knitr, which trips up alot of people with its default behavior of “working directory = directory where this file lives”. [...]

Install the here package:

install.packages("here")
library(here)
here()
here("construct","a","path")

Documentation of the here() function:

Starting with the current working directory during package load time, here will walk the directory hierarchy upwards until it finds a directory that satisfies at least one of the following conditions:

  • contains a file matching [.]Rproj$ with contents matching ^Version: in the first line
  • [... other options ...]
  • contains a directory .git

Once established, the root directory doesn't change during the active R session. here() then appends the arguments to the root directory.

The development version of the here package is available on github.

What about

What about files outside the project directory?

If you are loading or sourcing files outside the project directory, the recommended way is to use an environment variable at the Operating System level. Other users of your R code on different laptops or servers would need to set the same environment variable. The advantage is that it is portable.

data_path <- Sys.getenv("PROJECT_DATA")
df <- read.csv(file.path(data_path, "file_name.csv"))

Note: There is a long list of environmental variables which can affect an R session.

What about many projects sourcing each other?

It's time to create an R package.

10 Comments

This only works if you are sourceing or Rscripting a file in the same project tree. If you are calling a utility script for instance that lives somewhere else, this does not work.
Let's say that R is not made for actual reliable development. It is unbelievably hard to import relative to a given file path if you have multiple packages relying on each other. Your only option is to import everything from the root script globally. This is unacceptable for reliable development.
@PaulRougieux it's not about loading data. It's about importing other R files. e.g. having to use source(). compared to python import it's tragically bad, because you have to use very bad tricks to ensure a proper reliable import. This is very important when you have to write code that is production ready and thus have some degree of control.
@PaulRougieux it is also not a matter of package. You can't have nested hierarchies or have file A that imports file B within the same codebase (e.g. between pieces of code in different files that are part of the same package).
That's not how an R package works, you have a package name space and functions call each other within that name space.
|
9

Here is a custom function to obtain the path of a file in R, RStudio, or from an Rscript:

stub <- function() {}
thisPath <- function() {
  cmdArgs <- commandArgs(trailingOnly = FALSE)
  if (length(grep("^-f$", cmdArgs)) > 0) {
    # R console option
    normalizePath(dirname(cmdArgs[grep("^-f", cmdArgs) + 1]))[1]
  } else if (length(grep("^--file=", cmdArgs)) > 0) {
    # Rscript/R console option
    scriptPath <- normalizePath(dirname(sub("^--file=", "", cmdArgs[grep("^--file=", cmdArgs)])))[1]
  } else if (Sys.getenv("RSTUDIO") == "1") {
    # RStudio
    dirname(rstudioapi::getSourceEditorContext()$path)
  } else if (is.null(attr(stub, "srcref")) == FALSE) {
    # 'source'd via R console
    dirname(normalizePath(attr(attr(stub, "srcref"), "srcfile")$filename))
  } else {
    stop("Cannot find file path")
  }
}

https://gist.github.com/jasonsychau/ff6bc78a33bf3fd1c6bd4fa78bbf42e7

1 Comment

That is the only answer that works across all scenarios
9

If you're running an Rscript through the command-line etc

Rscript /path/to/script.R

The function below will assign this_file to /path/to/script

library(tidyverse)
get_this_file <- function() {
  commandArgs() %>%
    tibble::enframe(name = NULL) %>%
    tidyr::separate(
      col = value, into = c("key", "value"), sep = "=", fill = "right"
    ) %>%
    dplyr::filter(key == "--file") %>%
    dplyr::pull(value)
}
this_file <- get_this_file()
print(this_file)

1 Comment

It does not work for me, it returns character(0)
6

Another option to get current script path is funr::get_script_path() and you don't need run your script using RStudio.

6 Comments

What is funr?
it's a package, you can find more information about it here. In R, even if you don't attach a package in the current working environment, you can use their function by the following way package::function()
Let's say you have a script located in /path/to/project/script.R and inside that script you have a statement funr::get_script_path(), it will return a value of /path/to/project. Note: It is returning the full directory path of the current file and not the full path of the current file which should supposedlty /path/to/project/script.R. The function worked for my case though.
Returns NULL for me in RStudio
Returns NULL for me in vscode
|
4

Use the this.path library:

this.path::this.dir()

It has built-in compatibility for different IDEs and different use cases (running, sourcing, etc.)

Comments

3

The following solves the problem for three cases: RStudio source Button, RStudio R console (source(...), if the file is still in the Source pane) or the OS console via Rscript:

this_file = gsub("--file=", "", commandArgs()[grepl("--file", commandArgs())])
if (length(this_file) > 0){
  wd <- paste(head(strsplit(this_file, '[/|\\]')[[1]], -1), collapse = .Platform$file.sep)
}else{
  wd <- dirname(rstudioapi::getSourceEditorContext()$path)
}

print(wd)

3 Comments

adjusted for RStudio
It seems to be the best answer, as it covers all the options of execution.
@user890739 No, it actually only covers a tiny fraction of the possible options. This code absolutely does not work reliably.
2

I really like @Juan Bernabe's answer, but I converted it to base R to avoid tidyverse dependency, and also slightly simplified the code.

get_current_file_path <- function(){
  
  this_file <- grep("^--file=", commandArgs(), value = TRUE)
  
  this_file <- gsub("^--file=", "", this_file)
  
  if (length(this_file) == 0) this_file <- rstudioapi::getSourceEditorContext()$path
  
  return(dirname(this_file))
  
}

1 Comment

+1 for simplicity and elegance. If the dirname(this_file) part is wrapped in a normalizePath(...) call then the absolute path is returned which could be quite useful in certain scenarios.
1

I had trouble with all of these because they rely on libraries that I couldn't use (because of packrat) until after setting the working directory (which was why I needed to get the path to begin with).

So, here's an approach that just uses base R. (EDITED to handle windows \ characters in addition to / in paths)

args = commandArgs()

scriptName = args[substr(args,1,7) == '--file=']

if (length(scriptName) == 0) {
  scriptName <- rstudioapi::getSourceEditorContext()$path
} else {
  scriptName <- substr(scriptName, 8, nchar(scriptName))
}

pathName = substr(
  scriptName, 
  1, 
  nchar(scriptName) - nchar(strsplit(scriptName, '.*[/|\\]')[[1]][2])
)

Comments

1

The following code gives the directory of the running Rscript if you are running it either from Rstudio or from the command line using Rscript command:

if (rstudioapi::isAvailable()) {
  if (require('rstudioapi') != TRUE) {
    install.packages('rstudioapi')
  }else{
    library(rstudioapi) # load it
  }
 wdir <- dirname(getActiveDocumentContext()$path)
}else{
 wdir <- getwd()
}

setwd(wdir)

Comments

1

There's now a package for this

library(scriptName)
print(current_filename())
print(dirname(current_filename()))

4 Comments

Also this gives me NULL.
It would help to describe more about what you did to get the NULL. It still works for me. I am sourcing a script in RStudio. scriptName v1.0.1. It does give NULL if I run the script line-by-line rather than sourcing the whole script. I have not tried running from the command line.
I use Emacs/ESS. Since last update of ESS (from 2022 version to February/2025) getwd() gives the path level two levels higher than the script level. I assume that ESS does try to find a possible project structuer like git or similar to define a working directory. Nevertheless, I tried to look for a function which retrieves the path of the r-script. I tried several packages (scriptName, box, funr) but the give me all NULL. At the end I had to set a Lisp-Code in my Emacs-config to solve this problem.
I found this in reddit which says that Unfortunately R fundamentally has no way of getting the path of the current R script that works in all situations. It seems that there is no solution yet for non RStudio user.
1

The following code worked for me in these situations:

  • interactive
  • sourced in Rstudio console
  • sourced in Rstudio as background job
  • sourced from R GUI (not Rstudio)
  • from CLI (PowerShell) via Rscript
{if (any(str_detect(commandArgs(),
                    "interactive")))
  rstudioapi::getSourceEditorContext()$path
  else if (any(str_detect(commandArgs(),
                          "--file")))
  commandArgs() %>%
    .[str_which(.,
                "^--file")] %>%
    str_split_i("=",-1)
  else
    utils::getSrcFilename(\(dummy) {dummy},
                          full.names=TRUE)} %>%
  dirname()

Comments

-2

If you don't want to use (or have to remember) code, simply hover over the script and the path will appear

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.