中断/退出脚本

我有一个程序,做一些数据分析,是几百行长。

在程序的早期,我想做一些质量控制,如果没有足够的数据,我希望程序终止并返回到 R 控制台。否则,我希望执行剩下的代码。

我试过 breakbrowserquit,它们都没有停止程序其余部分的执行(而 quit停止执行同时完全退出 R,这是我不希望发生的)。我的最后一招是编写一份 if-else声明,内容如下:

 if(n < 500){}
else{*insert rest of program here*}

但这看起来像是糟糕的编程实践,我是不是漏掉了什么?

182127 次浏览

Reverse your if-else construction:

if(n >= 500) {
# do stuff
}
# no need for else

Edit: Seems the OP is running a long script, in that case one only needs to wrap the part of the script after the quality control with

if (n >= 500) {


.... long running code here


}

If breaking out of a function, you'll probably just want return(), either explicitly or implicitly.

For example, an explicit double return

foo <- function(x) {
if(x < 10) {
return(NA)
} else {
xx <- seq_len(x)
xx <- cumsum(xx)
}
xx ## return(xx) is implied here
}


> foo(5)
[1] 0
> foo(10)
[1]  1  3  6 10 15 21 28 36 45 55

By return() being implied, I mean that the last line is as if you'd done return(xx), but it is slightly more efficient to leave off the call to return().

Some consider using multiple returns bad style; in long functions, keeping track of where the function exits can become difficult or error prone. Hence an alternative is to have a single return point, but change the return object using the if () else () clause. Such a modification to foo() would be

foo <- function(x) {
## out is NA or cumsum(xx) depending on x
out <- if(x < 10) {
NA
} else {
xx <- seq_len(x)
cumsum(xx)
}
out ## return(out) is implied here
}


> foo(5)
[1] NA
> foo(10)
[1]  1  3  6 10 15 21 28 36 45 55

You could use the stopifnot() function if you want the program to produce an error:

foo <- function(x) {
stopifnot(x > 500)
# rest of program
}

Here:

if(n < 500)
{
# quit()
# or
# stop("this is some message")
}
else
{
*insert rest of program here*
}

Both quit() and stop(message) will quit your script. If you are sourcing your script from the R command prompt, then quit() will exit from R as well.

You can use the pskill function in the R "tools" package to interrupt the current process and return to the console. Concretely, I have the following function defined in a startup file that I source at the beginning of each script. You can also copy it directly at the start of your code, however. Then insert halt() at any point in your code to stop script execution on the fly. This function works well on GNU/Linux and judging from the R documentation, it should also work on Windows (but I didn't check).

# halt: interrupts the current R process; a short iddle time prevents R from
# outputting further results before the SIGINT (= Ctrl-C) signal is received
halt <- function(hint = "Process stopped.\n") {
writeLines(hint)
require(tools, quietly = TRUE)
processId <- Sys.getpid()
pskill(processId, SIGINT)
iddleTime <- 1.00
Sys.sleep(iddleTime)
}

Perhaps you just want to stop executing a long script at some point. ie. like you want to hard code an exit() in C or Python.

print("this is the last message")
stop()
print("you should not see this")

Edited. Thanks to @Droplet, who found a way to make this work without the .Internal(): Here is a way to implement an exit() command in R.

exit <- function() { invokeRestart("abort") }


print("this is the last message")
exit()
print("you should not see this")

Only lightly tested, but when I run this, I see this is the last message and then the script aborts without any error message.

Below is the uglier version from my original answer.

exit <- function() {
.Internal(.invokeRestart(list(NULL, NULL), NULL))
}

This is an old question but there is no a clean solution yet. This probably is not answering this specific question, but those looking for answers on 'how to gracefully exit from an R script' will probably land here. It seems that R developers forgot to implement an exit() function. Anyway, the trick I've found is:

continue <- TRUE


tryCatch({
# You do something here that needs to exit gracefully without error.
...


# We now say bye-bye
stop("exit")


}, error = function(e) {
if (e$message != "exit") {
# Your error message goes here. E.g.
stop(e)
}


continue <<-FALSE
})


if (continue) {
# Your code continues here
...
}


cat("done.\n")

Basically, you use a flag to indicate the continuation or not of a specified block of code. Then you use the stop() function to pass a customized message to the error handler of a tryCatch() function. If the error handler receives your message to exit gracefully, then it just ignores the error and set the continuation flag to FALSE.

I had a similar issue: Exit the current function, but not wanted to finish the rest of the code. Finally I solved it by a for() loop that runs only once. Inside the for loop you can set several differenct conditions to leave the current loop (function).

  for (i in T) {
print('hello')
if (leave.condition) next
print('good bye')
}