2

I've been searching for a while for a way to get the name of the currently executed script. Most answers I've seen were one of:

  1. Use commandArgs() - but this won't work for me because in RStudio commandArgs() does not return the filepath
  2. Define the name of the script as the top line and then use that in the rest of the script

I saw one mention of sys.frames() and found out that I can use sys.frame(1)$ofile to get the name of the currently executing script. I don't know much about these kinds of functions, so can anyone advise me if that's a bad a idea or when it can fail me?

Thanks

DeanAttali
  • 25,268
  • 10
  • 92
  • 118
  • How are you "running scripts"? What do you need the script name for? – MrFlick Feb 01 '15 at 02:33
  • You're right, that would matter. Using the RStudio "source" button. I need it because I want to be able to have a script that uses knitr on itself, and you need to pass in the script name. I want to have a generic code chunk that I can copy-n-paste into different scripts and it will automatically pick up the name – DeanAttali Feb 01 '15 at 02:35

2 Answers2

3

The problem is that R does't really run code as "scripts." When you "source" a file, it's basically like re-typing the contents of the file at the console. The exception is that functions can keep track of where they were sourced from.

So if you had a file like mycode.R that had

fn <- function(x) {
  x + 1 # A comment, kept as part of the source
}

and then you can do

source("mycode.R")
getSrcFilename(fn)
# [1] "mycode.R"

so in order to do that you just need to know a name of the function in the file. You could also make a function like this

gethisfilename <- function(z) {
    x<-eval(match.call()[[1]])
    getSrcFilename(x)
}

Assuming it's also in mycode.R, you can do

source("mycode.R")
gethisfilename()
# [1] "mycode.R"
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • That was very informative. I tried writing `print(sys.frame(1)$ofile)` in one R file, and your method in another file (`gethisfilename <- ...; print(gethisfilename())`) and noticed that they both work only when the file is saved and "Source"-ed. Are there any cases where one approach would work and the other won't, assuming I'm only interested in working from within RStudio? Your answer did make me see why doing this kind of thing is not common, so this is purely a curiosity question now. – DeanAttali Feb 02 '15 at 06:43
  • 1
    Well, `getSrcFilename` is documented and `$ofile` is not (as far as i can tell) so there's no guarantee that the latter behavior will be maintained in future releases. – MrFlick Feb 02 '15 at 06:45
  • Interesting solution, but as I understand it it only works if there are any functions in the sourced file. If you source file with no functions, it is probably better to go for this solution: http://stackoverflow.com/a/1816487/684229 – Tomas Feb 09 '15 at 17:44
  • Well, if you define the `gethisfilename` function in the file, then you'll always have at least one function. Plus as pointed out "ofile" is undocumented and it's behavior may change at any time. It's probably not a good idea to rely on an undocumented feature. – MrFlick Feb 09 '15 at 17:46
  • You can also use `getSrcDirectory` to get the path. I still maintain these things are better passed in from the caller... – Spacedman Feb 09 '15 at 17:47
  • 1
    @Spacedman I completely agree that these methods should not be necessary with better design choices. – MrFlick Feb 09 '15 at 17:49
2

Actually I think it is a bad idea, as I explained in my comment here: if you place this code in file1.R and then you source("file1.R") from file2.R, this will actually return "file2.R" instead of "file1.R", where it is called from!

So, to overcome this, you need to use sys.frames() and go for this solution: https://stackoverflow.com/a/1816487/684229

this.file.name <- function () # https://stackoverflow.com/a/1816487
{
    frame_files <- lapply(sys.frames(), function(x) x$ofile)
    frame_files <- Filter(Negate(is.null), frame_files)
    frame_files[[length(frame_files)]]
}

Then you can use this.file.name() in any script and it will return the correct answer! It doesn't depend how deep is the "source-stack". And also it doesn't depend where is the this.file.name() function defined. It will return the information of the source file where it's called from.

(and apart from MrFlick's interesting solution, this doesn't need any function to be defined in the file)

Community
  • 1
  • 1
Tomas
  • 57,621
  • 49
  • 238
  • 373