我有一个大的R脚本,比方说,142个小部分。如果一个部分失败并出现错误,我希望脚本继续而不是停止。这些部分不一定相互依赖,但有些部分相互依赖。如果中间的一个失败那没关系。我宁愿不用try()
来调用这个脚本。而且我不希望将文件拆分成许多较小的文件,因为每个部分都很短。
如果source()
可以像在R控制台上复制和粘贴那样工作,那就太好了。或者如果有办法将错误降级为警告,那也没关系。
一旦脚本运行,我打算grep(或类似)输出错误或警告文本,以便我可以看到已发生的所有错误或警告,而不仅仅是它已在第一个错误上停止。
我已阅读?source
并搜索了Stack Overflow的[R]标签。我发现了以下类似的问题,但try
和tryCatch
是提供的答案:
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?
由于上述原因,我不是在寻找try
或tryCatch
。这不适用于R包测试,我知道测试框架以及许多try()
或test_that()
调用(或类似)是完全合适的。这是我所描述的脚本的其他内容。
谢谢!
答案 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.
}