4

Is there a possibility to copy the executed lines or basically the script into the working directory?

So my normal scenario is, I have stand alone script which just need to be sourced within a working directory and they will do everything I need. After a few month, I made update to these scripts and I would love to have a snapshot from the script when I executed the source...

So basically file.copy(ITSELF, '.') or something like this.

drmariod
  • 11,106
  • 16
  • 64
  • 110
  • Maybe you could just change your approach slightly and use a small helper script that does something like `file.copy("myscript.r", paste0("snapshot_", Sys.Date(),"_myscript.r")); source("myscript.r")` – nrussell Jul 14 '15 at 13:44
  • Would work I guess, but isn't there a function to get it's own filename and path? I thought I used something like this in python, but this was using the command line. There I could get the first argument (filename). I wonder if source couldn't return something like this... – drmariod Jul 14 '15 at 13:46
  • I wouldn't surprise me if there was a function like this in Python, since Python provides useful meta features like the `__self__` attribute in class definitions. I'm not aware of something like what you describe above (`file.copy(ITSELF, '.')`) in R, but someone else may have a better solution. – nrussell Jul 14 '15 at 13:56
  • 1
    I just found a hint via this [link](http://stackoverflow.com/questions/1815606/rscript-determine-path-of-the-executing-script) but they already say it is kind of unstable but at the moment it seems to work. So the suggestion is to use `sys.frame(1)$ofile`. But to honest, I don't understand this, because sys.frame is not accessible in a way. – drmariod Jul 14 '15 at 14:03

3 Answers3

7

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)
CT Hall
  • 667
  • 1
  • 6
  • 27
Molx
  • 6,816
  • 2
  • 31
  • 47
  • Thanks Molx, this is what I just found but I do not completely understand the sys.frame function. Can you explain it a bit and why is it not possible to use in terminal? – drmariod Jul 14 '15 at 14:05
  • @drmariod I added some info to the answer. – Molx Jul 14 '15 at 14:24
  • Thanks for the additional information. I figured out, there are also variables `filename` and `srcfile` which seems to have the same information... Anyway, I will go for `ofile` since I also found some recommendations to use this. Thanks for the solution. – drmariod Jul 14 '15 at 14:31
  • For interactive you could use utils::savehistory: https://stat.ethz.ch/R-manual/R-devel/library/utils/html/savehistory.html . Even better would be to start using version control using git, subversion or similar. – Hansi Jul 14 '15 at 20:02
0

I just wanted to add my solution since I decided to use a try function before executing the copy command... Because I have the feeling I miss some control...

try({
  script_name <- sys.frame(1)$ofile
  copy_script_name <- 
    paste0(sub('\\.R', '', basename(script_name)),
           '_',
           format(Sys.time(), '%Y%m%d%H%M%S'),
           '.R')
  file.copy(script_name,
            copy_script_name)
})

This will copy the script into the current directory and also adds a timestamp to the filename. In case something goes wrong, the rest of the script will still execute.

drmariod
  • 11,106
  • 16
  • 64
  • 110
0

I originally posted this other thread, and I think it addresses your problem: https://stackoverflow.com/a/62781925/9076267

In my case, I needed a way to copy the executing file to back up the original >script together with its outputs. This is relatively important in research. What worked for me while running my script on the command line, was a mixure of >other solutions presented here, that looks like this:

library(scriptName)
file_dir <- paste0(gsub("\\", "/", fileSnapshot()$path, fixed=TRUE))
file.copy(from = file.path(file_dir, scriptName::current_filename()) ,
          to = file.path(getwd(), scriptName::current_filename()))

Alternatively, one can add to the file name the date and our to help in >distinguishing that file from the source like this:

file.copy(from = file.path(current_dir, current_filename()) ,
          to = file.path(getwd(), subDir, paste0(current_filename(),"_", Sys.time(), ".R")))

Marcos
  • 103
  • 6
  • The question ask for copying script back to the working directory. I see some of the parts might be relevant. Can you try to address that instead of copying it wholesale? Thanks a lot – StupidWolf Jul 07 '20 at 22:22
  • @StupidWolf if you want to copy the running script into the working directory, you just need to set `new_dir <- getwd()`. I will add that modification to my answer. But if you are talking about copying just parts of the script in a new file, then it won't work. But I guess the question was about copying the whole script, right? – Marcos Jul 08 '20 at 06:29