2

I have an R script that I call from an interactive bash shell (MacOS Catalina). This is one of a series of scripts that I call from the interactive shell, so I need to know if the initial script failed. It seems that no matter how the script fails (assert_that, stop, stopfinot, quit), R always returns an exit status of 0. How can I return a non-zero exist status from a failed R script?

Here is an example R script (fail.r).

#!/usr/bin/env Rscript

#library(assertthat)

message("Starting script")

#assert_that(FALSE)

#stop('Fail')

#stopifnot(FALSE)

q(save="no", status=10, runLast=FALSE)

message("Should not reach here")

And here is how I might call it from a bash prompt

src/poc/fail.r

echo $?

Regardless of the method I use to exit the R script $? always returns 0.

A couple other posts address this issue, but do not seem to apply to my situation (How to get an Rscript to return a status code in non-interactive bash mode) and (Make R exit with non-zero status code)

Ben Carlson
  • 1,053
  • 2
  • 10
  • 18

1 Answers1

3

I can get the status from Rscript back to the calling shell (R version 4.0.2, bash version 3.2.57 or zsh version 5.8 running on a MacBook Pro, macOS Mohave 10.14.6) using q(status = N). To get non-zero exit status from a failed R script, use q(status = 2) or higher, see quit:

$ Rscript -e 'q(status = 0);'
$ echo $?
0

$ Rscript -e 'q(status = 2);'
$ echo $?
2

$ Rscript -e 'q(status = 10);'
$ echo $?
10

$ R --version
R version 4.0.2 (2020-06-22) -- "Taking Off Again"
Copyright (C) 2020 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin13.4.0 (64-bit)

$ bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)

$ zsh --version
zsh 5.8 (x86_64-apple-darwin17.7.0)

Using a script essentially identical to the one you posted, I get the expected results (the status from quit is passed successfully to the enclosing shell):

Script:

#!/usr/bin/env Rscript

message("Starting script")
## Use status = 0, 2 or 10:
q(save = "no", status = 2, runLast = FALSE)
message("Should not reach here")

Output (tested with zsh and bash versions shown above):

$ ~/test/test1.r
Starting script
$ echo $?       
0
$ ~/test/test1.r
Starting script
$ echo $?       
2
$ ~/test/test1.r
Starting script
$ echo $?       
10

SEE ALSO:

Some error status values are used by R itself. The default error handler for non-interactive use effectively calls q("no", 1, FALSE) and returns error status 1. Error status 2 is used for R ‘suicide’, that is a catastrophic failure, and other small numbers are used by specific ports for initialization failures. It is recommended that users choose statuses of 10 or more.

Valid values of status are system-dependent, but 0:255 are normally valid.

(From quit docs)

Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47
  • Thanks @Timur your example helped me figure out what was wrong. Rscript was running .Rprofile, which loaded a bunch of packages and set some options. Something in there must have been preventing quit status from coming back. When I did Rscript --vanilla the quit status was returned correctly. Rscript --vanilla -e 'q(status = 2);' echo $? This also worked when calling a script using shebang: #!/usr/bin/env Rscript --vanilla – Ben Carlson Sep 17 '20 at 19:44
  • @BenCarlson I am glad that my answer was helpful! I recommend to make your comment into an answer, and accept your own answer (and thus un-accept my answer in the process). Your answer would help future users debug similar issues. It did not occur to me that `.Rprofile` and `Rscript --vanilla` were the key to the answer. I will keep my answer posted, of course, since it could be helpful to others as well. :) – Timur Shtatland Sep 17 '20 at 19:59