get filename and path of `source`d file

前端 未结 6 1752
心在旅途
心在旅途 2020-12-08 08:20

How can a sourced or Sweaved file find out its own path?

Background:

I work a lot with .R scripts or .Rnw files. My projects are o

相关标签:
6条回答
  • 2020-12-08 08:55

    Just FYI, knitr will setwd() to the dir of the input file when (and only when) evaluating the code chunks, i.e. if you call knit('path/to/input.Rnw'), the working dir will be temporarily switched to path/to/. If you want to know the input dir in code chunks, currently you can call an unexported function knitr:::input_dir() (I may export it in the future).

    0 讨论(0)
  • 2020-12-08 08:55

    Starting from gsk3's Seb's suggestions, here's an idea:

    • the combination of username (login) and IP or name of the computer could be used to select the right directory.

    That leads to something like:

        setwd (switch (paste (Sys.info () [c ("user", "nodename")], collapse="."), 
               user.laptop  = "~/Messungen",
               user2.server = "~/Projekte/Projekt/",
               ))
    

    So there is an automatic solution, that

    • works with source
    • works with Sweave
    • even works for interactive sessions where the commands are sent line by line

    • the combination of user and nodename of course needs to be specific

    • the paths need to be edited by hand, though.

    Improvements welcome!


    Update:

    Gabor Grothendieck answered the following to a related question on r-help today:

    this.dir <- dirname(parent.frame(2)$ofile)
    setwd(this.dir)
    

    which will work for source.


    Another update: I now do most of the data analysis work in RStudio. RStudio's projects basically solve the problem: RStudio changes the working directory to the project root directory every time I switch between projects.

    I can therefore put the project directory as far down my directory tree as I want (and the students can also put their copy wherever they want) and sync the data files and scripts/.Rnws via version control (We use a private git server). The RStudio project files are kept out of the version control, i.e. .gitignore contains .Rproj.user.

    Obviously, within the project, the directory structure needs to be synchronized.

    0 讨论(0)
  • 2020-12-08 08:57

    This answer works for source and also inside nvim-R - I have no idea if it works with knitr and similar things. Any feedback appreciated.

    If you have multiple scripts source-ing each other, it is important to get the correct one. That is, the largest i for which sys.frame(i)$ofile exists.

    get.full.path.to.this.sourced.script = function() {    
        for(i in sys.nframe():1) {  # Go through all the call frames,
                                    # in *reverse* order.
            x = sys.frame(i)$ofile
            if(!is.null(x))               # if $ofile exists,
                return(normalizePath(x))  #  then return the full absolute path
        }
    }
    
    0 讨论(0)
  • 2020-12-08 09:00

    An additional problem is that the working directory is a global variable, which can be changed by any script, so if your script calls another script, it will have to set the wd back. In RStudio I use Session -> Set Working Directory -> To Source File Location (I know, it's not ideal), and then my script does

    wd = getwd ()
    ...
    source ("mySubDir/myOtherScript.R", chdir=TRUE); setwd (wd)
    ...
    source ("anotherSubDir/anotherScript.R", chdir=TRUE); setwd (wd)
    

    In this way one can maintain a stack of working directories. I would love to see this implemented in the language itself.

    0 讨论(0)
  • 2020-12-08 09:02

    You can use sys.calls() to get the command used to source the file. Then you need a bit of trickery using regular expressions to get the pathname, bearing in mind that source("something/filename") could have used either the absolute or relative path. Here's a first attempt at putting all the pieces together: try inserting the following lines at the top of a source file.

    whereFrom=sys.calls()[[1]]
    # This should be an expression that looks something like
    # source("pathname/myfilename.R")
    whereFrom=as.character(whereFrom[2]) # get the pathname/filename
    whereFrom=paste(getwd(),whereFrom,sep="/") # prefix it with the current working directory
    pathnameIndex=gregexpr(".*/",whereFrom) # we want the string up to the final '/'
    pathnameLength=attr(pathnameIndex[[1]],"match.length")
    whereFrom=substr(whereFrom,1,pathnameLength-1)
    print(whereFrom) # or "setwd(whereFrom)" to set the working directory
    

    It's not very robust—for instance, it will fail on windows with source("pathname\\filename"), and I haven't tested what happens if you have one file sourcing another file—but you might be able to build a solution on top of this.

    0 讨论(0)
  • 2020-12-08 09:08

    I have no direct solution how to obtain the directory of the file itself but if you have a limited range of directories and directory structures you can probably use

     if(file.exists("c:/somedir")==TRUE){setwd("c:/somedir")}
    

    You could check out the pattern of the directory in question and then set the dir. Does this help you?

    0 讨论(0)
提交回复
热议问题