26

I've an R script, that takes commandline arguments, where the top line is:

#!/usr/bin/Rscript --slave

I wanted to interrupt execution in a function (so I can interactively use the data variables that have been loaded by that point to work out the next bit of code I need to write). I added this inside the function in question:

browser()

but it gets ignored. A bit of searching suggests it might be because the program is running in non-interactive mode. But even more searching has not tracked down how I switch the script out non-interactive mode so that browser() will work. Something like a browser_yes_I_really_mean_it() function.

P.S. I want to avoid altering the rest of the script if at all possible. My current approach is to copy and paste the code chunks, needed to prepare the data, into an interactive session; but as the script gets more and more complex this is getting more and more unreasonable.

UPDATE: for anyone else with the same question, it appears the answer to the actual question is that it is impossible. Once you start R in a non-interactive mode the die is cast. The given answers are therefore workarounds: either you hack your code (remembering to unhack it afterwards), or you refactor to make debugging easier. (This comment is not intended as a criticism of the answers; the suggested refactoring makes the code cleaner anyway.)

Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • Interrupt one really complex function? If these are several functions, you can do what mdsumner suggests below and source a bunch of scripts together inside another. Then after each reasonable breakpoint, write the data to disk. – Maiasaura Jan 05 '12 at 03:33
  • I think you are trying to go against fundamental logic here. Your top line means 'whatever the script says, don't interact'. That's the whole point. Change that line - how hard can it be? – reinierpost Jan 05 '12 at 11:53
  • @reinierpost Thanks, though that interpretation of `Rscript --slave` appears undocumented. The man page just says `--slave` is to make it quiet. But what to change it to? When I use just `Rscript` by itself then `browser()` does trigger but it exits the script, not giving me an interactive session. – Darren Cook Jan 06 '12 at 01:27
  • @DarrenCook, you could change the title of your question to e.g. "Debugging an R script ran through Rscript" and tweak your question a bit. I don't know what the general opinion is on editing questions when it turned out the focus changed in light of the anwers. – Paul Hiemstra Jan 06 '12 at 10:02
  • 1
    @PaulHiemstra I think editing questions is fine but, personally, I like failed questions and that Google will find them: knowing something cannot be done is more useful than knowing that something different can instead be done. (Because when searching I won't be searching for that "_something different_") – Darren Cook Jan 08 '12 at 01:55
  • I believe I was able to come up with a solution that is not a workaround but the actual way to run R code in a bash script in interactive mode - see my answer below. – Brunox13 May 20 '21 at 22:06

4 Answers4

22

Can you just fire up R and source the file instead?

R
source("script.R")
mdsumner
  • 29,099
  • 6
  • 83
  • 91
  • 1
    Thanks, but I had tried that. It complains about the missing commandline arguments then exits. – Darren Cook Jan 05 '12 at 03:56
  • 1
    Then why not just **first** paste in the command line arguments to an active R session, and **then** source in "script.R". With the addition of this one detail, @mdsumner's suggestion seems quite sound. – Josh O'Brien Jan 05 '12 at 06:09
  • Or create two R scripts, one that reads the cmd line arguments and sources the second. In the first script you could set a global option called interactive (using the options function). In the second script you can check this option (using getOption I think) and if it is FALSE, provide some defaults for the options you pass via the cmdline. In this way you can debug your second interactively and then run it in batch with the first. – Paul Hiemstra Jan 05 '12 at 10:59
  • I've expanded this answer, and Josh O'Brien's comment, in its own answer. – Darren Cook Jan 06 '12 at 03:08
  • 6
    It seems to me it would be useful to be able to launch R and have a command line argument like --SOURCE "source.R" that would do the same as having to TYPE CRAP INTO R MANUALLY. Are we programmers or are we secretaries? – Warren P Feb 02 '16 at 20:35
6

Following mdsumner's answer, I edited my script like this:

if(!exists("argv")){
    argv=commandArgs(TRUE)
    if(length(argv)!=4)usage_and_exit()
    }else{
    if(length(argv)!=4){
        stop("Must set argv as a 4 element vector. E.g. argv=c(...)")
        }
    }

Then no other change was needed, and I was able to do:

R
> argv=c('a','b','c','d')
> source("script.R")
Darren Cook
  • 27,837
  • 13
  • 117
  • 217
2

In addition to the previous answer, I'd create a toplevel function (e.g. doStuff) which performs the analysis you want to perform in batch. The function takes the cmd line options as input. In the batch script you source the script that contains this function and call it. In this way you can easily run the function in interactive mode and use e.g. browser().

mdsumner
  • 29,099
  • 6
  • 83
  • 91
Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
0

In some cases, the suggested solution (workaround) may not work - for example, when the R code needs to be run as a part of an existing bash script. For those cases, I suggest to write in your R script into the bash script using here document:

#!/bin/bash

R --interactive << EOT

# R code starts here
argv=c('a','b','c','d')
print(interactive())
# Rest of script contents

quit("no")
# R code ends here

EOT

This way, print(interactive()) above will yield TRUE.

Sidenote: Make sure to avoid the $ character in your R code, as this would not be processed correctly - for example, retrieve a column from a data.frame() by using df[["X1"]] instead of df$X1.

Brunox13
  • 775
  • 1
  • 7
  • 21