32

我知道该sink()函数可用于将 R 输出转移到文件中,例如

sink('sink-closing.txt')
cat('Hello world!')
sink()

是否有一个简单的命令来关闭所有未完成的接收器?

下面,我详细说明我的问题。

假设我的 R 脚本sink()在 R 脚本中打开了 a,但是在脚本关闭sink(). 我可能会多次运行 R 脚本,试图修复错误。最后,我想关闭所有接收器并打印到控制台。我该怎么做?

最后,为了具体起见,我提供一个 MWE 来说明我面临的问题。

首先,我编写了一个sink-closing.R包含错误的 R 脚本。

sink('sink-closing.txt')

foo <- function() {
  cat(sprintf('Hello world! My name is %s\n', 
              a.variable.that.does.not.exist))
}

foo()

sink()

接下来,我source多次使用 R 脚本,在尝试查找和修复错误时误说 3 次。

> source('~/Dropbox/cookbook/r-cookbook/sink-closing.R')
Error in sprintf("Hello world! My name is %s\n", a.variable.that.does.not.exist) : 
  object 'a.variable.that.does.not.exist' not found

现在,假设我正在调试 R 脚本并想要打印到控制台。我可以sink()多次调用以关闭较早的接收器。如果我调用它 3 次,那么我终于可以像以前一样打印到控制台了。但是我怎么知道我需要关闭多少个水槽?

4

4 回答 4

41
closeAllConnections()   # .........................
于 2013-09-11T03:39:43.697 回答
40

您可以使用sink.number()告诉您已经设置了多少转移,然后sink多次调用。把它放到一个函数中你可以有这个

sink.reset <- function(){
    for(i in seq_len(sink.number())){
        sink(NULL)
    }
}
于 2013-09-11T00:01:53.427 回答
9

基于@mnel 的评论:

sinkall <- function() {
  i <- sink.number()
  while (i > 0) {
    sink()
    i <- i - 1
  }
}

应关闭所有打开的水槽。

在处理设备和绘图时,您也可能会遇到此问题,其中未报告任何地方打开设备的数量。对于更一般的情况,您可以使用:

stopWhenError <- function(FUN) {
  tryCatch({
    while(TRUE) {
      FUN()
    }
  }, warning = function(w) {
    print("All finished!")
  }, error = function(e) {
    print("All finished!")
  })
}

stopWhenError(sink) # for sink.
stopWhenError(dev.off) # close all open plotting devices.

编辑: sink抛出警告而不是错误,所以我修改了代码,使其不会永远运行,哎呀!

于 2013-09-11T00:03:59.797 回答
0

我遇到的最常见的情况是发生错误,导致水槽无法关闭。例如,以下将在执行后留下一个打开的接收器。

sink("output.txt")
my_function_that_will_error()
sink()

这可以避免使用on.exit(sink()). 这将在“当前函数退出时(自然或由于错误)”关闭接收器(此处的文档)。

但是您必须更改顺序:

sink("output.txt")
on.exit(sink())
my_function_that_might_error()

所以我们创建了 sink,告诉 R 在它退出时关闭它,然后执行可能出错的代码。无论代码是否错误,这都会关闭接收器。

于 2021-11-11T22:37:36.790 回答