Debugging R脚本行号出错?

Debugging R脚本行号出错?,debugging,r,Debugging,R,如果我正在从命令行运行一个长的R脚本(R--slave script.R),如何让它在出现错误时给出行号 如果可能的话,我不想在脚本中添加调试命令——我只想让R的行为与大多数其他脚本语言一样…这不会给出行号,但它会告诉您调用堆栈中发生故障的位置,这非常有帮助: traceback() [编辑:]从命令行运行脚本时,必须跳过一个或两个调用,请参阅 如果没有常见的调试疑点,我不知道还有其他方法可以做到这一点: 调试() 浏览器() 选项(error=recover)[后跟选项(error=NULL

如果我正在从命令行运行一个长的R脚本(R--slave script.R),如何让它在出现错误时给出行号


如果可能的话,我不想在脚本中添加调试命令——我只想让R的行为与大多数其他脚本语言一样…

这不会给出行号,但它会告诉您调用堆栈中发生故障的位置,这非常有帮助:

traceback()
[编辑:]从命令行运行脚本时,必须跳过一个或两个调用,请参阅

如果没有常见的调试疑点,我不知道还有其他方法可以做到这一点:

  • 调试()
  • 浏览器()
  • 选项(error=recover)[后跟选项(error=NULL)将其还原]
  • [编辑:]抱歉…刚才看到您正在从命令行运行此操作。在这种情况下,我建议使用选项(错误)功能。下面是一个简单的例子:

    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=)
    
    xdo
    options(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)