Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set value of --args from within R session

I would like to use the evaluate package to simulate executing (lots of) r-scripts while recording the outputs using evaluate. Evaluate is designed to do exactly this and it works almost out of the box. However, when using Rscript, the user passes arguments via the command line --args which are retrieved in R using the base::commandArgs function.

Is there any sensible way I can override the value of --args from within a running R session such that an R script using base::commandArgs() would work as expected without having to modify the script itself?

like image 695
Jeroen Ooms Avatar asked Jun 20 '13 06:06

Jeroen Ooms


3 Answers

Here is the @spacedman answer as a simple Rcpp-based implementation. We have to do some gymnastics on the on the vector to get it into char** format:

#include "Rcpp.h"
#include "R_ext/RStartup.h"

// [[Rcpp::export]]
void setCmdArgs(std::vector<std::string> x) {
  std::vector<char*> vec(x.size());
  for (unsigned int i=0; i<x.size(); i++) 
    vec[i] = const_cast<char*>(x[i].c_str());
  R_set_command_line_arguments(x.size(), static_cast<char**>(&(vec[0])));
}

/*** R
setCmdArgs(c("hello", "world"))
commandArgs()
setCmdArgs(c("good", "bye", "my", "friend"))
commandArgs()
*/

If you save this in a file and pull it in via a single call to sourceCpp(), then the R snippet at the bottom is executed too:

R> sourceCpp("/tmp/spacedman.cpp")

R> setCmdArgs(c("hello", "world"))

R> commandArgs()
[1] "hello" "world"

R> setCmdArgs(c("good", "bye", "my", "friend"))

R> commandArgs()
[1] "good"   "bye"    "my"     "friend"
R> 
like image 58
Dirk Eddelbuettel Avatar answered Oct 18 '22 06:10

Dirk Eddelbuettel


I had a delve into R's guts and came up with some smelly intestines to play with.

The command line is copied from C's argc/argv into a global C variable with this function in the source code:

void R_set_command_line_arguments(int argc, char **argv)

So we need a little C wrapper to get round the fact that the first parameter isn't a pointer:

#include "R.h"
#include "R_ext/RStartup.h"
void set_command(int *pargc, char **argv){
  R_set_command_line_arguments(*pargc, argv);
}

compile in the usual way:

R CMD SHLIB setit.c

load, call:

> dyn.load("setit.so")
> commandArgs()
[1] "/usr/lib/R/bin/exec/R"
> invisible(.C("set_command",as.integer(2),c("Foo","Bar")))
> commandArgs()
[1] "Foo" "Bar"

from then on commandArgs() will return that vector until you change it.

like image 26
Spacedman Avatar answered Oct 18 '22 05:10

Spacedman


At the top of your script you set commandArgs to be TRUE, if you don't pass anything on the command line the variable will be of length 0 so use an if statement to assign some values when you are not actually passing command line arguments. If you need to be careful about using default values you can set a flag to print a message when you use default values of command line args.

args <- commandArgs(TRUE)
argDefault <- FALSE
if( length(args) == 0 ){
   args <- whatever you want
   argDefault <- TRUE
}
res <- 2 * args[1]
if( argDefault )
      simpleWarning(message="No command args were passed: Use of default values")  
like image 21
Simon O'Hanlon Avatar answered Oct 18 '22 07:10

Simon O'Hanlon