有没有办法`source()`并在出错后继续?

时间:2013-01-30 19:33:17

标签: r

我有一个大的R脚本,比方说,142个小部分。如果一个部分失败并出现错误,我希望脚本继续而不是停止。这些部分不一定相互依赖,但有些部分相互依赖。如果中间的一个失败那没关系。我宁愿不用try()来调用这个脚本。而且我不希望将文件拆分成许多较小的文件,因为每个部分都很短。

如果source()可以像在R控制台上复制和粘贴那样工作,那就太好了。或者如果有办法将错误降级为警告,那也没关系。

一旦脚本运行,我打算grep(或类似)输出错误或警告文本,以便我可以看到已发生的所有错误或警告,而不仅仅是它已在第一个错误上停止。

我已阅读?source并搜索了Stack Overflow的[R]标签。我发现了以下类似的问题,但trytryCatch是提供的答案:

R Script - How to Continue Code Execution on Error
Is there any way to have R script continue after receiving error messages instead of halting execution?

由于上述原因,我不是在寻找trytryCatch。这不适用于R包测试,我知道测试框架以及许多try()test_that()调用(或类似)是完全合适的。这是我所描述的脚本的其他内容。

谢谢!

3 个答案:

答案 0 :(得分:19)

为了使这个更具体,以下怎么样?

首先,要测试该方法,请创建一个包含多个语句的文件(称为"script.R"),第一个语句在评估时会抛出错误。

## script.R

rnorm("a")
x <- 1:10
y <- 2*x

然后将其解析为表达式列表,并依次评估每个元素,将评估包含在对tryCatch()的调用中,以便错误不会造成太大的损害:

ll <- parse(file = "script.R")

for (i in seq_along(ll)) {
    tryCatch(eval(ll[[i]]), 
             error = function(e) message("Oops!  ", as.character(e)))
}
# Oops!  Error in rnorm("a"): invalid arguments
# 
# Warning message:
# In rnorm("a") : NAs introduced by coercion
x
# [1]  1  2  3  4  5  6  7  8  9 10
y
# [1]  2  4  6  8 10 12 14 16 18 20

答案 1 :(得分:12)

评估包提供了evaluate()功能的另一个选项。它不像我的其他建议那么轻巧,但是 - 作为支撑 knitr 的功能之一 - 它已经过了你所希望的测试!

library(evaluate)

rapply((evaluate(file("script.R"))), cat)  # For "script.R", see my other answer
# rnorm("a")
# NAs introduced by coercionError in rnorm("a") : invalid arguments
# In addition: Warning message:
# In rnorm("a") : NAs introduced by coercion
x
#  [1]  1  2  3  4  5  6  7  8  9 10
y
#  [1]  2  4  6  8 10 12 14 16 18 20

对于看起来更像您在命令行中实际键入语句的输出,请使用replay()。 (感谢hadley提示):

replay(evaluate(file("script.R")))
# >
# > rnorm("a")
# Warning message:
# NAs introduced by coercion
# Error in rnorm("a"): invalid arguments
# > x <- 1:10
# > y <- 2*x

修改

replay()还提供了一种更好的方式来回放错误和警告,如果这些只是你需要的那些:

## Capture the output of evaluate()
res <- evaluate(file("script.R"))

## Identify those elements inheriting from "error" or "warning
ii <- grepl("error|warning", sapply(res, class))   

## Replay the errors and warnings
replay(res[ii])
# Warning message:
# NAs introduced by coercion
# Error in rnorm("a"): invalid arguments
# > 

答案 2 :(得分:5)

这是笨重的,并且使用了无人的朋友eval(parse(,但可能会有所帮助。乔什的答案更清晰。

# assign the filepath
fn <- "c:/path/to your/script.R"

# read in the whole script
z <- readLines( fn )

# set a starting j counter
j <- 1

# loop through each line in your script..
for ( i in seq(length(z)) ) {

    # catch errors
    err <- try( eval( parse( text = z[j:i] ) ) , silent = TRUE )

    # if it's not an error, move your j counter up to one past i
    if ( class( err ) != 'try-error' ) j <- i + 1 else

    # otherwise, if the error isn't an "end of input" error,
    # then it's an actual error and needs to be just plain skipped.
    if ( !grepl( 'unexpected end of input' , err ) ) j <- i + 1

    # otherwise it's an "end of line" error, which just means j alone.
}