How Can a Script Find Itself in R Running from the Command Line

How can a script find itself in R running from the command line?

Below is a solution that will give you the correct file directory path when the script is run either with source or with Rscript.

# this is wrapped in a tryCatch. The first expression works when source executes, the
# second expression works when R CMD does it.
full.fpath <- tryCatch(normalizePath(parent.frame(2)$ofile), # works when using source
error=function(e) # works when using R CMD
normalizePath(unlist(strsplit(commandArgs()[grep('^--file=', commandArgs())], '='))[2]))
dirname(full.fpath)

The key to this is the function normalizePath. Given a relative or abbreviated path name, normalizePath will return a valid path or raise an error. When running the script from Rscript, if you give normalizePath the base filename of the current script, it'll return the fullpath, regardless of what your current directory is. It even gets the path right when you supply a relative path to R CMD and there's a script with the same name in the current directory!

In the code above, I extract the filename from one of the strings returned by commandArgs. If you take a look at the output of commandArgs, you'll see that the filename is the 4th argument. The argument is recorded as '--file=yourscript.R', so in the final line above, I split the string on '=' and pull out the file name.

Problems executing script from command line in R. Error message: cannot find path specified

Thanks @sebastian-c! I tried to use RScript, which I investigated before. However, the problem was a different one. Appears that in my installation there is a R.exe and Rscript.exe file in .\bin, but also one in .\bin\x64. The first one is not working properly, but the second one is. The comment made by @Roland is very important as well, since once working I got this error message!

The following command did the job:

"C:\Program Files\R\R-2.15.2\bin\x64\Rscript.exe" "C:\Users\jdd\Documents\test.R"

and the corrected text.R is:

setwd("C:\\Users\\jdd\\Documents")
test <- 2*6598
filename = "test.csv"
write.csv(test,file=filename)

In R, how to trace/log commands before executing them

I don't think Rscript by itself is going to do what you want, but there is a way. Let me walk you through finding that way.

I'll start with a naive script in foo.R:

1+1
2*3

How can we call Rscript?

$ Rscript --help
Usage: /path/to/Rscript [--options] [-e expr [-e expr2 ...] | file] [args]

--options accepted are
--help Print usage and exit
--version Print version and exit
--verbose Print information on progress
--default-packages=list
Where 'list' is a comma-separated set
of package names, or 'NULL'
...

Noticing the --verbose, I try:

$ Rscript --verbose foo.R
running
'/usr/lib/R/bin/R --no-echo --no-restore --file=foo.R'

[1] 2
[1] 6

Not yet, but ... --no-echo seems interesting. Let me mimic those arguments and use R directly:

$ R --no-restore --file=foo.R

R version 4.0.5 (2021-03-31) -- "Shake and Throw"
Copyright (C) 2021 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> 1+1
[1] 2
> 2*3
[1] 6

After reading the output from R --help, we can silence some of that by adding --quiet:

$ R --quiet --no-restore --file=foo.R
> 1+1
[1] 2
> 2*3
[1] 6

R command for setting working directory to source file location in Rstudio

To get the location of a script being sourced, you can use utils::getSrcDirectory or utils::getSrcFilename. These require a function as an input. Create a script with the following lines, and source it to see their usage:

print(utils::getSrcDirectory(function(){}))
print(utils::getSrcFilename(function(){}, full.names = TRUE))

Changing the working directory to that of the current file can be done with:

setwd(getSrcDirectory(function(){})[1])

This does not work in RStudio if you Run the code rather than Sourceing it. For that, you need to use rstudioapi::getActiveDocumentContext.

setwd(dirname(rstudioapi::getActiveDocumentContext()$path))

This second solution requires that you are using RStudio as your IDE, of course.

Copy script after executing

I think this is what you're looking for:

file.copy(sys.frame(1)$ofile,
to = file.path(dirname(sys.frame(1)$ofile),
paste0(Sys.Date(), ".R")))

This will take the current file and copy it to a new file in the same directory with the name of currentDate.R, so for example 2015-07-14.R

If you want to copy to the working directory instead of the original script directory, use

file.copy(sys.frame(1)$ofile,
to = file.path(getwd(),
paste0(Sys.Date(), ".R")))

Just note that the sys.frame(1)$ofile only works if a saved script is sourced, trying to run it in terminal will fail. It is worth mentioning though that this might not be the best practice. Perhaps looking into a version control system would be better.

Explanation:

TBH, I might not be the best person to explain this (I copied this idea from somewhere and use it sometimes), but I'll try. Basically in order to have information about the script file R needs to be running it as a file inside an environment with that information, and when that environment is a source call it contains the ofile data. We use (1) to select the next (source()'s) environment following the global environment (which is 0). When you're running this from terminal, there's no frame/environment other than Global (that's the error message), since no file is being ran - the commands are sent straight to terminal.

To illustrate that, we can do a simple test:

> sys.frame(1)
Error in sys.frame(1) : not that many frames on the stack

But if we call that from another function:

> myf <- function() sys.frame(1)
> myf()
<environment: 0x0000000013ad7638>

Our function's environment doesn't have anything in it, so it exists but, in this case, does not have ofile:

> myf <- function() names(sys.frame(1))
> myf()
character(0)


Related Topics



Leave a reply



Submit