Debugging R脚本行号出错?
如果我正在从命令行运行一个长的R脚本(R--slave script.R),如何让它在出现错误时给出行号Debugging R脚本行号出错?,debugging,r,Debugging,R,如果我正在从命令行运行一个长的R脚本(R--slave script.R),如何让它在出现错误时给出行号 如果可能的话,我不想在脚本中添加调试命令——我只想让R的行为与大多数其他脚本语言一样…这不会给出行号,但它会告诉您调用堆栈中发生故障的位置,这非常有帮助: traceback() [编辑:]从命令行运行脚本时,必须跳过一个或两个调用,请参阅 如果没有常见的调试疑点,我不知道还有其他方法可以做到这一点: 调试() 浏览器() 选项(error=recover)[后跟选项(error=NULL
如果可能的话,我不想在脚本中添加调试命令——我只想让R的行为与大多数其他脚本语言一样…这不会给出行号,但它会告诉您调用堆栈中发生故障的位置,这非常有帮助:
traceback()
[编辑:]从命令行运行脚本时,必须跳过一个或两个调用,请参阅
如果没有常见的调试疑点,我不知道还有其他方法可以做到这一点:
options(error = quote({dump.frames(to.file=TRUE); q()}))
您可以在错误条件下创建任意复杂的脚本,因此您应该决定调试所需的信息
否则,如果有您关心的特定区域(例如连接到数据库),则将它们包装在tryCatch()函数中。在R 2.10及更高版本中将提供对此的支持。邓肯·默多克(Duncan Murdoch)于2009年9月10日刚刚向r-devel发布了关于: 我刚刚向R-devel添加了几个函数来帮助 调试
findLineNum()
查找函数的哪一行
对应于特定的源代码行<代码>setBreakpoint()接受
findLineNum
的输出,并调用trace()
设置断点
在那里
这些依赖于代码中包含源代码引用调试信息。
这是source()
读取的代码的默认值,但不适用于包。
要获取包代码中的源引用,请设置环境
变量R\u KEEP\u PKG\u SOURCE=yes
,或在R内设置
选项(keep.source.pkgs=TRUE)
,然后从源代码安装程序包
代码。阅读?findLineNum
,了解如何告诉它进行搜索的详细信息
在包内,而不是将搜索限制在全局
环境
比如说,
x <- " f <- function(a, b) {
if (a > b) {
a
} else {
b
}
}"
eval(parse(text=x)) # Normally you'd use source() to read a file...
findLineNum("<text>#3") # <text> is a dummy filename used by
parse(text=)
xdooptions(error=traceback)
提供了有关导致错误的行内容的更多信息。如果有错误,它会导致出现回溯,对于某些错误,它有行号,前缀为#
。但它是命中或未命中的,许多错误不会得到行号 您可以通过设置
options(show.error.locations = TRUE)
我只是想知道为什么这个设置不是R中的默认设置?应该是这样,就像其他语言一样。指定用于处理非灾难性错误的全局R选项对我来说很有效,同时还提供了一个自定义的工作流,用于保留有关错误的信息并在失败后检查此信息。我目前运行的是R版本3.4.1。
下面,我介绍了为我工作的工作流,以及我用来在R中设置全局错误处理选项的一些代码
正如我所配置的,错误处理还会创建一个RData文件,其中包含出错时工作内存中的所有对象。可以使用load()
将此转储读回R,然后使用debugger(errorDump)
以交互方式检查出错时存在的各种环境
我会注意到,我能够从堆栈中的任何自定义函数中获取traceback()
输出中的行号,但前提是我在调用脚本中使用的任何自定义函数时使用了keep.source=TRUE
选项。如果没有此选项,如下设置全局错误处理选项会将traceback()
的完整输出发送到名为error.log
的错误日志,但行号不可用
以下是我在工作流程中采取的一般步骤,以及在非交互式R失败后如何访问内存转储和错误日志
我将以下内容放在从命令行调用的主脚本的顶部。这将为R会话设置全局错误处理选项。我的主脚本名为myMainScript.R
。代码中的各行后面都有注释,说明它们所做的事情。基本上,使用此选项,当R遇到触发stop()
的错误时,它将创建一个RData(*.rda)在目录~/myUsername/directoryForDump
中的所有活动环境中转储工作内存文件,并将名为error.log
的错误日志以及一些有用信息写入同一目录。您可以修改此代码段以添加其他错误处理(例如,向转储文件和错误日志文件名添加时间戳等)
确保在主脚本和任何后续函数调用中,无论何时源函数,都使用选项keep.source=TRUE
。也就是说,要生成函数的源代码,可以使用source('~/path/to/myFunction.R',keep.source=TRUE)
。这是traceback()
输出包含行号所必需的。看起来您还可以使用选项(keep.source=TRUE)
全局设置此选项,但我还没有测试它是否有效。如果不需要行号,可以省略此选项
从终端(R外部),使用Rscript myMainScript.R
以批处理模式调用主脚本。这将启动一个新的非交互式R会话,并运行脚本myMainScript.R
。步骤1中给出的代码段位于myMainScript.R
的顶部,用于设置非交互式R会话的错误处理选项
在执行myMainScript.R
时遇到错误。这可能在主脚本本身中,也可能嵌套了多个函数。当
setBreakpoint("<text>#3")
options(show.error.locations = TRUE)
options(error = quote({
setwd('~/myUsername/directoryForDump'); # Set working directory where you want the dump to go, since dump.frames() doesn't seem to accept absolute file paths.
dump.frames("errorDump", to.file=TRUE, include.GlobalEnv=TRUE); # First dump to file; this dump is not accessible by the R session.
sink(file="error.log"); # Specify sink file to redirect all output.
dump.frames(); # Dump again to be able to retrieve error message and write to error log; this dump is accessible by the R session since not dumped to file.
cat(attr(last.dump,"error.message")); # Print error message to file, along with simplified stack trace.
cat('\nTraceback:');
cat('\n');
traceback(2); # Print full traceback of function calls with all parameters. The 2 passed to traceback omits the outermost two function calls.
sink();
q()}))
Error in callNonExistFunc() : could not find function "callNonExistFunc"
Calls: test_multi_commodity_flow_cmd -> getExtendedConfigDF -> extendConfigDF
Traceback:
3: extendConfigDF(info_df, data_dir = user_dir, dlevel = dlevel) at test_multi_commodity_flow.R#304
2: getExtendedConfigDF(config_file_path, out_dir, dlevel) at test_multi_commodity_flow.R#352
1: test_multi_commodity_flow_cmd(config_file_path = config_file_path,
spot_file_path = spot_file_path, forward_file_path = forward_file_path,
data_dir = "../", user_dir = "Output", sim_type = "spot",
sim_scheme = "shape", sim_gran = "hourly", sim_adjust = "raw",
nsim = 5, start_date = "2017-07-01", end_date = "2017-12-31",
compute_averages = opt$compute_averages, compute_shapes = opt$compute_shapes,
overwrite = opt$overwrite, nmonths = opt$nmonths, forward_regime = opt$fregime,
ltfv_ratio = opt$ltfv_ratio, method = opt$method, dlevel = 0)