It is convenient to be able to set the working directory of a script to its parent directory. This allows you to point to the relative path of files associated with it. For example, if your working directory is set to the location of init.sh
, then you will be able to read in data/file.dat
without specifying its full path. If these files are in a git repo - you can also be assured they will travel together.
├── init.sh
└── data
└── file.dat
In bash you can set the directory to the location of the script being executed using:
cd "${0%/*}"
# Or more obviously
cd "$(dirname "${BASH_SOURCE[0]}")"
In python you can set the directory to the location of the script being executed using:
import os
from os.path import dirname, abspath
os.chdir(dirname(abspath(__file__)))
In R, unfortunately, no straightforward method exists Update 2020-06-29 - there is a way to do this; see the 2020-06-29 update below. The update below demonstrates how to get the current directory a script is located in, followed by additional ways of setting the working directory based on the git repo or with Rstudio.
Update: 2020-06-29 - A way to get the script directory in R
There is a way to set the working directory to a script location, as shown here, you can get the location of a script using the function below.
LocationOfThisScript = function() # Function LocationOfThisScript returns the location of this .R script (may be needed to source other files in same dir)
{
this.file = NULL
# This file may be 'sourced'
for (i in -(1:sys.nframe())) {
if (identical(sys.function(i), base::source)) this.file = (normalizePath(sys.frame(i)$ofile))
}
if (!is.null(this.file)) return(dirname(this.file))
# But it may also be called from the command line
cmd.args = commandArgs(trailingOnly = FALSE)
cmd.args.trailing = commandArgs(trailingOnly = TRUE)
cmd.args = cmd.args[seq.int(from=1, length.out=length(cmd.args) - length(cmd.args.trailing))]
res = gsub("^(?:--file=(.*)|.*)$", "\\1", cmd.args)
# If multiple --file arguments are given, R uses the last one
res = tail(res[res != ""], 1)
if (0 < length(res)) return(dirname(res))
# Both are not the case. Maybe we are in an R GUI?
return(NULL)
}
current.dir = LocationOfThisScript()
setwd to script location when calling Rscript
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)
}
# Setting the script path would then be:
setwd(getScriptPath())
setwd to script location in Rstudio
# This will not throw an error if you are not using rstudio.
try(setwd(dirname(rstudioapi::getActiveDocumentContext()$path)))
Setting the script path relative to the git repo
Most of my code resides in git repositories - so an alternative to setting the working directory to the location of a script is to set it to the location of a git repository. Here is how I do that in R:
# First set the working directory to the location of a script (useful for working in Rstudio)
try(setwd(dirname(rstudioapi::getActiveDocumentContext()$path)))
# Next, set the directory relative to the git repo
setwd(system("git rev-parse --show-toplevel", intern=T))
The big advantage of this approach is that you can call the script from anywhere while you are located in its git repo, and it will always execute from the base or top-level of that repo.