72

In one R file, I plan to source another R file that supports reading two command-line arguments. This sounds like a trivial task but I couldn't find a solution online. Any help is appreciated.

7
  • Dirk, I already searched but could not any related one in StackOverflow. I saw you answered many R related questions. Thanks your contributions. Commented Jan 25, 2013 at 16:08
  • Do you have any control over the file that reads two command-line argumetns? Commented Jan 25, 2013 at 16:35
  • Do you mean command-line arguments from the bash shell or from the R console? Commented Jan 25, 2013 at 16:41
  • Why would you want to do this? The reason to source(file) is to load things into your workspace. If you want to execute the sourced object, better to do so in the next command. Commented Jan 25, 2013 at 17:19
  • To answer the comments from GSee and Seth. I wrote the R script being sourced, which is used inside Bash shell. Commented Jan 25, 2013 at 17:43

6 Answers 6

66

I assume the sourced script accesses the command line arguments with commandArgs? If so, you can override commandArgs in the parent script to return what you want when it is called in the script you're sourcing. To see how this would work:

file_to_source.R

print(commandArgs())

main_script.R

commandArgs <- function(...) 1:3
source('file_to_source.R')

outputs [1] 1 2 3

If your main script doesn't take any command line arguments itself, you could also just supply the arguments to this script instead.

Sign up to request clarification or add additional context in comments.

6 Comments

redefining commandArgs() function looks a smart solution. I tried this and it works.
@MatthewPlourde I am not understanding how this works, I have to pass file paths as arguments and I have one single r script.What do you mean with parent and sourced script?
@user4050 This questions and answer deal with the case of executing one R script from within another. If you're running an R script from the command-line just use the commandArgs() function.
This works well but fails when the call to commandArgs from file to source uses the trailingOnly argument. To fix this I found this is more useful in general: commandArgs <- function(...) 1:3 where ... absorbs any unused arguments.
I think this is a very poor solution, because what you do is to redefine the commandArgs() function.
|
30

The simplest solution is to replace source() with system() and paste. Try

arg1 <- 1
arg2 <- 2
system(paste("Rscript file_to_source.R", arg1, arg2))

4 Comments

You are right, this is simple, but it won't bring the objects that file_to_source.R produces into globalenv(). For that, it seems to me, you need Matthew Plourde's hack -- redefine commandArgs, and maybe rm() your version immediately after calling source().
system doc says "This interface has become rather complicated over the years: see system2 for a more portable and flexible interface which is recommended for new code."
Isn't it possible to define an environment where the arguments desired are defined, and then source the script within that environment, so that the correct parameters are found? Then you would only have to extend source by another parameter (of vector type), and it would all work like magic.
@U.Windl: if I understand correctly what you mean, that acutally already works... see the answer by GSee
10

If you have one script that sources another script, you can define variables in the first one that can be used by the sourced script.

> tmpfile <- tempfile()
> cat("print(a)", file=tmpfile)
> a <- 5
> source(tmpfile)
[1] 5

1 Comment

This is the most straightforward approach - useful for those new to R. All variables set in the calling script are available to any sourced script. Powerful flexibility in R.
5

An extended version of @Matthew Plourde's answer. What I usually do is to have an if statement to check if the command line arguments have been defined, and read them otherwise.

In addition I try to use the argparse library to read command line arguments, as it provides a tidier syntax and better documentation.

file to be sourced

 if (!exists("args")) {
         suppressPackageStartupMessages(library("argparse"))
         parser <- ArgumentParser()
         parser$add_argument("-a", "--arg1", type="character", defalt="a",
               help="First parameter [default %(defult)s]")
         parser$add_argument("-b", "--arg2", type="character", defalt="b",
               help="Second parameter [default %(defult)s]")
         args <- parser$parse_args()
 }

 print (args)

file calling source()

args$arg1 = "c" 
args$arg2 = "d"
source ("file_to_be_sourced.R")

c, d

1 Comment

I use a slight variation of this, which allows me to only have to declare args I want to modify from the defaults: args <- parser$parse_args(); if (exists('myargs')) { args <- purrr::list_modify(args, !!!myargs) }
1

This works:

# source another script with arguments
source_with_args <- function(file, ...){
  commandArgs <<- function(trailingOnly){
    list(...)
  }
  source(file)
}

source_with_args("sourcefile.R", "first_argument", "second_argument")

Note that the built in commandArgs function has to be redefined with <<- instead of <-. As I understand it, this makes its scope extend beyond the function source_with_args() where it is defined.

3 Comments

Note that the above code worked fine to do what I wanted (pass arguments to a sourced R-script as if they were command line arguments.) Now when I try to repeat, I get this error: "cannot change value of locked binding for 'commandArgs' Any comments on why this worked at first but now it doesn't?
get error => Error in <<-: cannot change value of locked binding for 'commandArgs'
Not for me. I'm using R 4.1.2
0

I've tested some of the alternatives here and I end up with this:

File calling the source:

source_with_args <- function(file, ...){
  system(paste("Rscript", file, ...))
}
source_with_args(
  script_file,
  paste0("--data=", data_processed_file),
  paste0("--output=", output_file)
)

File to be sourced:

  library(optparse)
  option_list = list(
    make_option(
      c("--data"),
      type="character",
      default=NULL,
      help="input file",
      metavar="filename"
    ),
    make_option(
      c("--output"),
      type="character",
      default=NULL,
      help="output file [default= %default]",
      metavar="filename"
    )
  )
  opt_parser = OptionParser(option_list=option_list)
  data_processed_file <- opt$data
  oputput_file <- opt$output
  if(is.null(data_processed_file) || is.null(oputput_file)){
    stop("Required information is missing")
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.