在 RStudio / Interactive R 会话中出错时停止执行

Make execution stop on error in RStudio / Interactive R session

在 RStudio 中执行代码块时,发生错误时执行实际上不会停止。例如,如果我在打开的编辑器中有以下代码:

x <- 'test'
stopifnot(is.numeric(x))
print('hello world')

和 运行 它(使用命令-return 或单击 "Run" 按钮),它会打印错误,然后继续执行打印语句。

有没有办法将 RStudio 配置为不继续处理错误?即让它停在上面的第 2 行而不继续打印语句?

编辑:刚刚意识到,如果我使用 command-R 在标准 R GUI 中发送代码块,也会发生这种情况。

我不认为有什么方法可以阻止 RStudio 运行 宁所有行,当你 select 一个部分并按 Ctrl+Enter 时。 Rstudio 只是 运行 一行接一行。即使在函数内部调用 stopifnot(),该函数调用之后的所有行仍将被计算。

如果您的目标只是在出现问题时得到通知,那么在大量代码 运行 白费之前,也许您可​​以定义一个类似于 stopifnot() 的函数,它将直接进入无限循环,如果有错误。然后,您可以在 RStudio 中按 Esc 或 Stop-Button 来中断程序。像这样:

waitifnot <- function(cond) {
  if (!cond) {
    message(deparse(substitute(cond)), " is not TRUE")  
    while (TRUE) {}
  }
}

现在,您可以 运行 使用此函数的示例代码:

x <- 'test'
waitifnot(is.numeric(x))
print('hello world')

正如预期的那样,hello world 从未被打印出来。您会收到一条错误消息,告诉您出了点问题,然后程序会一直等到您手动中止它。

这在交互模式以外的任何情况下都无法正常工作。为了避免不愉快的情况,你也可以让函数有不同的反应,如果它不在交互模式下使用,例如这样:

waitifnot <- function(cond) {
  if (!cond) {
    msg <- paste(deparse(substitute(cond)), "is not TRUE")
    if (interactive()) {
      message(msg)
      while (TRUE) {}
    } else {
      stop(msg)
    }
  }
}

只有在交互模式下运行该函数才会进入死循环。否则,它将通过调用 stop() 简单地中止执行。我已经检查过使用 Ctrl+Enter 或 RStudio 中的 Source 按钮(无限循环)以及 Bash 命令行上的 Rscript(程序中止)是否按预期工作。

如@lmo 所述,您只需按下按钮 Source 而不是 select 全部 + Run。事实上,您甚至不需要保存脚本文件就可以点击 Source 按钮。

但问题确实是 Source 将始终 运行 整个脚本。所以如果你真的只想 运行 脚本中的一个块,这对你没有帮助。

解决此问题的一种方法是在遇到错误时将 R 'error' 选项配置为 运行 自定义函数。

错误处理函数示例可以使用 Sys.sleep 暂停 R 的执行并等待用户输入(例如,通过按 ctrl-C 或 Escape 中断 运行ning 函数在我的 Mac).

上的 R-Studio 中

通常情况下,R 会继续执行任何后续命令。但是,我们可以通过定义一个函数来防止这种情况发生,该函数将 'eat' 所有这些,这样它们就不会得到 运行。为了让这个更流畅,我们可以在每个 'eaten' 行之后输出一个 'cursor up' 字符序列,当下一个输出时,它会擦除​​它们中的每一个,这样 not-运行 行不要弄乱 terminal/console.

示例代码:

# Define our error-handling pause function:

pause=function(){
    on.exit(eat_input())
    cat("Paused: press ctrl-C (or Escape key in Rstudio) to continue\n")
    cat("(any subsequent code will be ignored)\n")
    Sys.sleep(Inf)
}

# Define our 'eat_input' function to prevent output of subsequent, not-run input:

eat_input=function(){
    cat("3[1A")
    while((x=readline())!='')cat("3[1A")
}

# Set the 'error' option to execute our pause function:

options(error=pause)

试试看:

print("Before the error")

# an error: we want to stop after this
xxx

# some more input: we don't want this to be run or to appear in the console
print("After the error")

要关闭此行为,只需将错误选项重新设置为 NULL:

options(error=NULL)