Write access to commandArgs? - r

I know that I can use commandArgs to read the command line arguments passed to a script in R, but I would like to debug a command line script by sourceing it in R and making it run using custom command line arguments. Is there a way of modifying the command line arguments without modifying the script file?
My scripts are normally using the optparse package for actual argument parsing, if that helps.

I'll try and expand what I said in a comment.
The python way of writing scripts usually involves detecting if the file is being run as a script, handling the args, and then calling functions defined in the file. Something like:
def foo(x):
return x*2
if __name__=="__main__":
v = sys.argv[1]
print foo(v)
This has the advantage that you can import the file into an interactive python session and the code in the 'if' block doesn't run. You can then test the foo function interactively.
Now is there a way you can check in R if the file is being run as a script, or being sourced from an interactive session?
foo=function(x){
return(x*2)
}
if(!interactive()){
x = as.numeric(commandArgs(trailingOnly=TRUE)[1])
print(foo(x))
}
If run with Rscript argtest.R 22 will print 44, if you run R interactively and do source("argtest.R") it won't run the code in the if block. Its a nice pattern.

How about simply overwriting it with your own definition, e.g.
commandArgs <- function(trailingOnly=FALSE) {
args<- c("/foo/bar", "baz")
# copied from base:::commandArgs
if (trailingOnly) {
m <- match("--args", args, 0L)
if (m)
args[-seq_len(m)]
else character()
}
else args
}

The simplest solution is to replace source() with system(). Try
system("Rscript file_to_source.R 1 2 3")

Related

Is there a way to debug an R script run from the command line with Rscript.exe

Is it possible to debug an R source file which is executed with Rscript.exe?
> Rscript.exe mysource.R various parameters
Ideally, I would like to be able to set a break-point somewhere in the mysource.R file in RStudio.
Is entering the R debugger directly at the command line possible for instance by adding some debug directive to the source file?
Maybe sourcing the file from R would work? How? How do I pass the command line arguments "various parameters" so that commandArgs() returns the correct values?
The mysource.R could look as follows (in practice it is much more complicated).
#!/usr/bin/Rscript
args <- commandArgs(trailingOnly=TRUE)
print(args)
As far as debugging from console is concerned there are few questions related to it without an answer.
Is there a way to debug an RScript call in RStudio? and Rscript debug using command line
So, I am not sure if something has changed and if it is now possible.
However, we can debug from sourcing the file by using a hack. You could add browser() in the file wherever you want to debug. Consider your main file as :
main.R
args <- commandArgs(trailingOnly=TRUE)
browser()
print(args)
Now, we can override the commandArgs function and pass whatever arguments we want to pass which will be passed when you source the file.
calling_file.R
commandArgs <- function(...) list(7:9, letters[1:3])
source("main.R")
After running the source command, you could debug from there
Called from: eval(ei, envir)
#Browse[1]> args
#[[1]]
#[1] 7 8 9
#[[2]]
#[1] "a" "b" "c"
There's no native way to debug Rscript in the command line, but you can use a kind of hacky workaround I whipped up with readLines and eval.
ipdb.r <- function(){
input <- ""
while(!input %in% c("c","cont","continue"))
{
cat("ipdb.r>")
# stdin connection to work outside interactive session
input <- readLines("stdin",n=1)
if(!input %in% c("c","cont","continue","exit"))
{
# parent.frame() runs command outside function environment
print(eval(parse(text=input),parent.frame()))
}else if(input=="exit")
{
stop("Exiting from ipdb.r...")
}
}
}
Example usage in an R file to be called with Rscript:
ipdbrtest.R
a <- 3
print(a)
ipdb.r()
print(a)
Command line:
$ Rscript ipdbrtest.R
[1] 3
ipdb.r>a+3
[1] 6
ipdb.r>a+4
[1] 7
ipdb.r>a <- 4
[1] 4
ipdb.r>c
[1] 4
If you're considering using R instead of Rscript, you could pass it environment variables and retrieve them with Sys.getenv().

Run Multiple Scripts with Error Handling in R

I need to run two R scripts in sequence. I am not asking about running scripts in parallel.
Each script has a stop-if-error logic inside. So if I run either of them separately, the execution will halt when an error occurs. The problem is, when I put them in a wrapper code like this:
source('script1.r', echo=T)
source('script2.r', echo=T)
and when an error occurs in script1.r, R will move on to execute script2.r.
How do I tell R to stop completely and not to move on in such a scenario?
I would wrap the code in the two scripts in functions, source the scripts and then call the functions in the main file. If one function fails the script should stop.
(This may depend on how you execute the script, for example if you select code in Rstudio and run by CMD+Enter it will continue after errors.)
You could do something with try(). I put the following in script1.R:
stop("Stop")
In script2.R I have
print("A")
Then from a "master script", I call
x <- try(source("script1.R", echo = TRUE))
#>
#> > stop("Stop")
if ( !inherits(x, "try-error") ) {
source("script2.R", echo = TRUE)
}
Created on 2019-01-31 by the reprex package (v0.2.1)
If the stop() portion is called (or any error occurs), x will be of class try-error, and the second source() call will not be executed.

calling an Rscript from node.js

I have been trying to execute an Rscript from my node.js server. tried to follow an example online, but i keep getting a null returned object or sometimes the process keeps running forever. I have mentioned the code snippet below. Thank you.
example.js ::
var R = require("r-script");
var out = R("scripts/testScript.R")
.data("hello world", 20)
.callSync(function(err,resp){
console.log(out);
});
testScript.R file :::
needs(magrittr)
set.seed(512)
do.call(rep, input) %>%
strsplit(NULL) %>%
sapply(sample) %>%
apply(2, paste, collapse = "")
For windows users:
You need to add the environment variable to Windows's %PATH% variable. R-script package needs to call "R" command from the CMD. If R.exe is not set as a environment vairable, then it will never be able to call the "R" command from anywhere.
Look up how to add environment variables to Windows, and remember: if the path to the folder containing the executables has a white space, it must be added between double quotes. "C:\Program Files\R\R-3.3.2\bin\x64"
If you have already done this but the problem persists, I can only think of two reasons:
There's something wrong with your R method and it's giving an internal exception inside the R session.
The system can't find the file. Maybe check the filepath.
You can use child processes in node to call other languages. I find it easiest to call Python from node, and use Python's subprocess module to then call R:
NODE
var spawn = require("child_process").spawn
var process = spawn('python',["call_r.py", script_choice, function_choice]);
This calls our call_r.py file passing along our script and function choices:
PYTHON (call_r.py)
import subprocess
import sys
script_choice = sys.argv[1]
function_choice = sys.argv[2]
call_script = 'R_Scripts/' + script_choice + '.R'
cmd = ['Rscript', call_script] + [function_choice]
result = subprocess.check_output(cmd, universal_newlines=True)
print(result)
sys.stdout.flush()
This parses the passed script and function choices, calling R via Python's subprocess module.
R (script that was chosen)
myArgs <- commandArgs(trailingOnly = TRUE)
function_choice <- myArgs[1]
# add your R functions here
eval(parse(text=function_choice))
Here, R parses the passed function choice and evaluates it. Note that arguments can be passed to the R function of choice by simply including them in the function argument (e.g. my_function('hey there'))

R Script as a Function

I have a long script that involves data manipulation and estimation. I have it setup to use a set of parameters, though I would like to be able to run this script multiple times with different sets of inputs kind of like a function.
Running the script produces plots and saves estimates to a csv, I am not particularly concerned with the objects it creates.
I would rather not wrap the script in a function as it is meant to be used interactively.
How do people go about doing something like this?
I found this for command line arguments : How to pass command-line arguments when source() an R file but still doesn't solve the interactive problem
I have dealt with something similar before. Below is the solution I came up with.
I basically use list2env to push variables to either the global or function's local environment
and I then source the function in the designated environment.
This can be quite useful especially when coupled with exists as shown in the example below which would allow you to keep your script stand-alone.
These two questions may also be of help:
Source-ing an .R script within a function and passing a variable through (RODBC)
How to pass command-line arguments when source() an R file
# Function ----------------------------------------------------------------
subroutine <- function(file, param = list(), local = TRUE, ...) {
list2env(param, envir = if (local) environment() else globalenv())
source(file, local = local, ...)
}
# Example -----------------------------------------------------------------
# Create an example script
tmp <- "test_subroutine.R"
cat("if (!exists('msg')) msg <- 'no argument provided'; print(msg)", file = tmp)
# Example of using exists in the script to keep it stand-alone
subroutine(tmp)
# Evaluate in functions environment
subroutine(tmp, list(msg = "use function's environment"), local = TRUE)
exists("msg", envir = globalenv()) # FALSE
# Evaluate in global environment
subroutine(tmp, list(msg = "use global environment"), local = FALSE)
exists("msg", envir = globalenv()) # TRUE
unlink(tmp)
Just to clarify what was alluded to in Hansi's comment, here is one approach to this issue:
Wrap the script into a function, since this will let you go up one level of abstraction if needed, and will also make it easier to call the function whenever it is needed in any other script.
In cases where you want to use the script interactively, you can put a browser() call somewhere in your script. At the point where browser() is called, the function will pause and keep the environment as-is within the function, and you can then step through the function and use R interactively from within the function.
In the base package, check ?commandArgs, you can use this to parse out arguments from the command line.
If I have a script, test.R, containing the code:
args <- commandArgs(trailingOnly=TRUE)
for (arg in args){
print(arg)
}
and I call it from the command line with rscript as follows:
rscript test.R arg1 arg2 arg3
The output is:
[1] "arg1"
[1] "arg2"
[1] "arg3"

Call a function in R Script from a Batch file

I've a batch file that calls R script. It works fine. I need to know how Can I Call a function in R Script from that Batch file in windows? How to call this Function with parameters:
PNLCalcMultipleDatesClient("2010-10-03", "2010-10-05", "XYZ")
This command line works but it doesn't have Function call that is in R Script. Can you please help me to modify this command line in Windows and call above function ?
"\\C1PRDTLS01.axinc.com\Dev\RiskClient\inputCData\PNLCalculation\R\R-3.1.1\bin\R.exe" CMD BATCH --no-save --no-restore "\\C1PRDTLS01.axinc.com\Dev\RiskClient\inputCData\PNLCalculation\RScript\RadarPNLTimeseries.R"
Here is the R Script:
PNLCalcMultipleDatesClient("2010-10-03", "2010-10-05", "Dunavant")
PNLCalcMultipleDatesClient <- function(begindate, enddate, Client)
{
# Do some operation here....
.....
......
}
Here is an example. Here is the Rscript that i have, i tend to save them as txt itself.
## Rscript: Passing arguments to the Rscripts likes args[i]
#!/usr/bin/env Rscript
args = commandArgs(trailingOnly=TRUE)
print(1:args[1])
df=data.frame(1:args[1])
write.csv(df, args[2])
Then your batch file would look like this. Then you feed those arguments either directly to a cmd or create a batch file out of it.
echo off
Rscript rparam.txt 1000 out.csv
For your case, your Rscript(R_with_par.R) would be:
#!/usr/bin/env Rscript
args = commandArgs(trailingOnly=TRUE)
x1=args[1]
x2=args[2]
x3=args[3]
PNLCalcMultipleDatesClient <- function(begindate, enddate, Client)
{
# Do some operation here....
.....
......
}
PNLCalcMultipleDatesClient(as.Date(x1), as.Date(x2), as.character(x3))
And your CMD command would be:
Rscript R_with_par.R 2010-10-03 2010-10-05 Dunavant
You have to make sure that parameters that you pass are in format required by R. Give the path of the R script if you are not in the same directory. Also Rscript is far better choice than R CMD.
Create R Function:
squared <- function(number) {
sqred <- number^2
cat(sqred)
}
squared(as.integer(commandArgs(trailingOnly = TRUE)))
Run R script from command prompt: (Your path could be different)
C:R/bin/RScript.exe" "C:/Rscript/command_line.R" 100
Note: First argument is path of Rscript.exe, Second Argument is path of your R script and third argument is function argument.

Resources