Determine path of the executing script

142,917

Solution 1

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.

Solution 2

You can use the commandArgs function to get all the options that were passed by Rscript to the actual R interpreter and search them for --file=. If your script was launched from the path or if it was launched with a full path, the script.name below will start with a '/'. Otherwise, it must be relative to the cwd and you can concat the two paths to get the full path.

Edit: it sounds like you'd only need the script.name above and to strip off the final component of the path. I've removed the unneeded cwd() sample and cleaned up the main script and posted my other.R. Just save off this script and the other.R script into the same directory, chmod +x them, and run the main script.

main.R:

#!/usr/bin/env Rscript
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)
other.name <- file.path(script.basename, "other.R")
print(paste("Sourcing",other.name,"from",script.name))
source(other.name)

other.R:

print("hello")

output:

burner@firefighter:~$ main.R
[1] "Sourcing /home/burner/bin/other.R from /home/burner/bin/main.R"
[1] "hello"
burner@firefighter:~$ bin/main.R
[1] "Sourcing bin/other.R from bin/main.R"
[1] "hello"
burner@firefighter:~$ cd bin
burner@firefighter:~/bin$ main.R
[1] "Sourcing ./other.R from ./main.R"
[1] "hello"

This is what I believe dehmann is looking for.

Solution 3

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

Solution 4

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

Don't ask me how it works though, because I've forgotten :/

Solution 5

This works for me

library(rstudioapi)    
rstudioapi::getActiveDocumentContext()$path
Share:
142,917

Related videos on Youtube

Frank
Author by

Frank

Updated on May 05, 2022

Comments

  • Frank
    Frank about 2 years

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

    #!/usr/bin/env Rscript
    message("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?

    • Frank
      Frank over 14 years
      No. :( I haven't seen any solution that actually works. Apart from the workaround to just pass the directory in or use an environment variable.
    • Frank
      Frank over 14 years
      I hate having to rely on environment variables.
    • aL3xa
      aL3xa almost 14 years
      Try with system("locate other.R")... but be sure to give your script a unique name... O_o (assuming that you use UNIX system and that locate command is available)
    • Etienne Low-Décarie
      Etienne Low-Décarie about 12 years
      This would be amazing to make scripts fully portable and executable by even R neofites!
    • Etienne Low-Décarie
      Etienne Low-Décarie about 12 years
      It appears like all the answers require you to input the path at some point (at least to source the file)! It would be great if you could send someone a compressed folder and running any R script file within that folder would read from and save to that folder.
    • Giacomo
      Giacomo over 6 years
      this single issue could actually become te reason why I could completely move to Python
    • Michael Barton
      Michael Barton over 6 years
      @giac_man, I feel R is full of hundreds of tiny problems like this that all add up to making very difficult to work in.
    • mjs
      mjs over 4 years
      in Matlab there is the magic command 'mfilename' swich gives you the file name of currently running code. It cannot be so difficult to add something like that in R!
    • M_Merciless
      M_Merciless over 3 years
      Great package from @Andrew , perfect for logging purposes. Many thanks for putting this on CRAN.
  • Suppressingfire
    Suppressingfire over 14 years
    In what context does that work? print(sys.frames()) turns up NULL when I run it.
  • Richie Cotton
    Richie Cotton over 14 years
    @Suppressingfire: sys.frames returns the environments of the call stack, so it only really makes sense when called from a function. Try, e.g., foo <- function() {bar <- function() print(sys.frames()); bar()}; foo(). I can't figure out @hadley's code though because environments don't have an ofile member.
  • hadley
    hadley over 14 years
    You have to source the file in - i.e. if I save that code then run source("~/code/test.r"), PATH will be set to ~/desktop. If you just evaluate it at the top level, it will return NULL.
  • hadley
    hadley over 14 years
    I downmodded because your technique doesn't work with source as I thought the OP wanted - but maybe I misread his/her requirement. But I can't un-downmod :( Sorry!
  • Suppressingfire
    Suppressingfire over 14 years
    But actually, it does work fine with source! Just source(other.name) and it works properly.
  • Suppressingfire
    Suppressingfire over 14 years
    I think maybe we're talking at cross purposes. I think we have different understandings of what the dehmann is interested in doing.
  • Frank
    Frank over 14 years
    This does not answer my question. I need to automatically find the "other.R" file. x$ofile is undefined, so frame_files is empty.
  • Etienne Low-Décarie
    Etienne Low-Décarie about 12 years
    This requires you to have the script path. It does not allow you to make a truly portable R script that can run from anywhere.
  • Sim
    Sim almost 12 years
    @hadley, very useful code. I was able to generalize the "reload current script" utility function I add to almost all scripts when they are in active development. RScript reloader
  • Jason
    Jason over 9 years
    For path concatenation, better to use other.name <- file.path(script.basename, "other.R")
  • Ehsan88
    Ehsan88 over 9 years
    It doesn't work for me. I run R in Windows. Any idea?
  • this.is.not.a.nick
    this.is.not.a.nick over 9 years
    You always have to save the document befor running the script. Maybe is this the problem.
  • wch
    wch over 9 years
    I like this because it works with both Rscript and source() within R. I'd suggest doing normalizePath() on both versions, so that it gives the full path in both cases.
  • The Unfun Cat
    The Unfun Cat about 9 years
    This did not work recursively; the file I source looks for a data file (but in the wrong directory).
  • RalfB
    RalfB almost 9 years
    Got the same error, with a saved scriptt and freshly installed and run R 3.2.0 on windows...
  • Murta
    Murta almost 9 years
    This error happens when you try to execute dirname(sys.frame(1)$ofile) directly from Rstudio. It works ok when the script is executed using source("other.R"), and dirname(sys.frame(1)$ofile) is inside "other.R".
  • Ahmed Laatabi
    Ahmed Laatabi over 8 years
    it's working under Mac.. this should be executed from a script file, nit directly from R terminal
  • user9869932
    user9869932 over 8 years
    This option works fine in Mac with R-Studio. Thank-you!
  • Mark Adamson
    Mark Adamson about 8 years
    I got the 'not that many frames on the stack' error when calling as a script with rscript.exe i.e. not using source(). so I had to instead use the solution from Suppressingfire below
  • jcarlos
    jcarlos about 8 years
    For me, your solution was the best. Specially because it could be applied to a Shiny app and that one on link not.
  • davidski
    davidski almost 8 years
    Did not work for me as well (Win10, fresh R.3.3.0, ran from cmd line). Answer from @Suppressingfire below worked fine.
  • Mark Adamson
    Mark Adamson almost 8 years
    This doesn't work when using debugSource as the relevant property is then fileName rather than oFile. Just needs some simple if statements to get around it as shown in other solutions posted here like stackoverflow.com/a/32016824/538403
  • Mark Adamson
    Mark Adamson almost 8 years
    source in Rstudio gave ofile for me, but debugSource gave fileName so your solution works well but the code comments aren't quite right in my case
  • O.rka
    O.rka over 7 years
    This is the only thing that worked. Note, for this to work library(base) took me a while to figure that out lol
  • RubenLaguna
    RubenLaguna over 7 years
    Here the getSrcDirectory is utils::getSrcDirectory
  • user1071847
    user1071847 over 7 years
    Nope. That finds the directory of the process, not the file itself.
  • Paul
    Paul over 7 years
    I gel NULL when this is placed in server.R when using shiny
  • Paul
    Paul over 7 years
    When I try to run commandArgs(trailingOnly = FALSE) inside server.R in a shiny application, I get [1] "RStudio" "--interactive". No information about the directory it was called from.
  • PeterVermont
    PeterVermont about 7 years
    I do not see ofile but do see fileName
  • geneorama
    geneorama almost 7 years
    This worked for me in windows, in linux, but then it failed when I called it from crontab. SAD!
  • ManicMailman
    ManicMailman almost 7 years
    Doesn't work with interactive R session; I'm getting: ``` > source("csf.R") > csf() Error: RStudio not running ```
  • theforestecologist
    theforestecologist almost 7 years
    what is "ofile"??
  • Contango
    Contango almost 7 years
    This might work nicely under Linux/Mac, but it did not work for me in an interative RStudio session under Windows. sourceDir was blank.
  • Contango
    Contango almost 7 years
    This worked for me in Windows with RStudio in interactive mode.
  • John Haberstroh
    John Haberstroh over 6 years
    @EtienneLow-Décarie It does not require the script path, it gets it from bash. The main issue is that it is not a reliable way to get the path. Something like this is preferred, as in stackoverflow.com/questions/59895/… path_to_script="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
  • Michael Barton
    Michael Barton over 6 years
    I still get the error "Error in sys.frame(1) : not that many frames on the stack "
  • nJGL
    nJGL over 6 years
    Not from within RStudio, though, except when sourcing
  • Pranasas
    Pranasas over 6 years
    After all these years I consider this to be the best and cleanest answer.
  • pommedeterresautee
    pommedeterresautee over 6 years
    @Contango on an interactive terminal, there is no path!!! You want the path to a file.
  • Ufos
    Ufos over 6 years
    SOLUTION: user@laptop_model:~$ R -e 'source("/home/user/[path_to_file].R")' -- relative paths work like magic
  • bokov
    bokov about 6 years
    It always returns NA, even if I create a script that prints its output and then call the script e.g. with R -e "library(getopt); testscript.R"
  • Ryan C. Thompson
    Ryan C. Thompson about 6 years
    As the name of the function implies, you need to run your script using Rscript.
  • bokov
    bokov about 6 years
    Ah, oops. Thanks.
  • Vince W.
    Vince W. about 6 years
    you sir get my vote, because this is the solution that worked for me
  • Ista
    Ista over 5 years
    This only works from inside RStudio I guess. Trying from the terminal I get Error: RStudio not running.
  • quest
    quest over 5 years
    For me this works sometimes while rest of the time I get Error in path.expand(path) : invalid 'path' argument error.
  • Andrew
    Andrew about 5 years
    This solution didn't work for me with Rscript dir/foo.R. It did work with R -e "source('dir/foo.R')".
  • Kim
    Kim about 5 years
    If this helps anyone, for the original post, that would mean source(file.path(dirname(thisFile()), "other.R")) in foo.R. This works for me.
  • Bojan P.
    Bojan P. almost 5 years
    Package ‘scriptName’ was removed from the CRAN repository. - what now? :o
  • Wassadamo
    Wassadamo almost 5 years
    One issue. Suppose in RStudio I source main.R which sources helper.R which calls thisFile(). It will fetch the path of main.R instead of helper.R. Any tips here?
  • abalter
    abalter almost 5 years
    I'm getting character(0). Suggestions?
  • Ron
    Ron over 4 years
    For me the here package do exactly the job and seems to be an easy solution
  • Boops Boops
    Boops Boops over 4 years
    This did not work for me on a Linux machine; instead of returning the path of the file, it returned the directory I was currently located in. I created a test script called TEST.R with one line of code: print(fileSnapshot()$path) I saved it in this folder: /opt/home/boops/Desktop/Testfolder/TEST.R I then navigated to my desktop and tried to run the file: boops@linuxserver:~/Desktop$ Rscript /opt/home/boops/Desktop/Testfolder/TEST.R [1] "/opt/home/boops/Desktop"
  • Colombo
    Colombo about 4 years
    As I just figured what I want on how sys.frames work from previous answer, I have found this solution. sys.frames() will get stack of environment from the most recent to the oldest one. This include source, which will set the ofile atribute, and non sourced environment, such as functions, which do not have ofile atribute. This will simply find the latest environment with the ofile atribute. Brilliant.
  • altabq
    altabq about 4 years
    I get an error message readLink: illegal option -- e usage: readLink [-FlLnqrsx] [-f format] [-t timefmt] [file ...]
  • Kay
    Kay almost 4 years
    more specifically it works, if run from a R script in R studio. Even on the console in RStudio it will not give the right result "" in my case
  • Joe Flack
    Joe Flack almost 4 years
    Didn't work for me either. Returns the same thing as 'here()' when using the 'here' library. It returned the path to my currently open R project, but not he very file itself being executed.
  • Joe Flack
    Joe Flack almost 4 years
    This is great. Can someone make a package?
  • Patrick
    Patrick almost 4 years
    This works while running interactively in Rstudio as long as you don't change the document in focus. If you submit lines to run and then switch to another document while they run, the path to the other document will be returned.
  • Patrick
    Patrick almost 4 years
    This works while running interactively in Rstudio as long as you don't change the document in focus. If you submit lines to run and then switch to another document while they run, the path to the other document will be returned.
  • Andrew
    Andrew over 3 years
    I've uploaded a package named "this.path" to CRAN, it should solve this issue!
  • johnny
    johnny over 3 years
    When running this command on RGui, I get the following message. Any idea on how to get around it? Error in this.path::this.path() : 'this.path' used in an inappropriate fashion * no appropriate 'source' or 'sys.source' call was found up the calling stack * R is being run from RGui which requires a 'source' and 'sys.source' call on the calling stack
  • Andrew
    Andrew over 3 years
    I hadn't realized until you commented that you could run code from within a script from 'RGui', I thought previously that the only way to run code within a script from 'RGui' was to use 'source'. I'm looking into a fix for this issue, hopefully I'll find something soon. For now, you could use 'RStudio' to edit and run your scripts because I know it works from there. Sorry for the lack of an answer, but thank you for pointing out this bug!
  • Andrew
    Andrew over 3 years
    @johnny I believe I found a solution, but it only works on a Windows OS. I'm attempting to find a solution for the macOS version of "RGui" named "AQUA", and then I'll upload the update to the package to CRAN. It'll be about ~10 business days before the update is approved for release by one of the CRAN maintainers, hopefully 'RStudio' is working for you in the meantime!
  • Andrew
    Andrew over 3 years
    @johnny the update was released a few hours ago, much sooner than I was expecting. I've tested on two separate computers now, it seems to work as intended from 'RGui'!
  • johnny
    johnny over 3 years
    Just tested v.0.2.0 on a script file saved in an RGui session, and it works for me. Thanks!
  • Andrew
    Andrew over 3 years
    @JoeFlack I've made a package for this called "this.path", you can find it on CRAN at CRAN.R-project.org/package=this.path
  • Andrew
    Andrew over 3 years
    This only works when using source or sys.source, and it always grabs the first source on the stack, not the most recent.
  • Andrew
    Andrew over 3 years
    @Wassadamo you could try package "this.path", it handles nested source calls correctly
  • Andrew
    Andrew over 3 years
    fileSnapshot()$path just returns the path of the current working directory, not the path of the executing script. Another thing, on Windows it is unnecessary to substitute the backslashes with forward slashes, but on a Unix-alike OS it is dangerous to do this since filenames can contain backslashes. Last thing, you should not have a path separator at the end of your path since R will no longer recognize the string as a path (as returned by 'file.exists').
  • user5359531
    user5359531 over 2 years
    This is the correct answer. Really baffling how many people are wasting time with the other proposed answers to this.
  • htlbydgod
    htlbydgod about 2 years
    This does not work for me on Mac
  • understorey
    understorey almost 2 years
    In windows/Rstudio it returns character(0)
  • understorey
    understorey almost 2 years
    This does not work for me in RStudio/Windows from sys.frames()[[1]]$ofile I get NULL.