禁用cat命令

15

假设我有以下函数:

## Just an example
f = function() { 
  for(i in 1:10000)
      cat(i)
  return(1)
}

当我调用f()时,有没有一种方法可以停止cat在屏幕上打印(不改变函数本身的任何方式)?

提问原因

我的学生上传他们的R文件。然后我运行这些脚本并检查它们是否正确。偶尔会有学生留下cat命令。如果这个命令出现在一个很长的for循环中,那么这将特别烦人。

5个回答

20

在Linux上,您可以使用sink()调用将输出重定向到/dev/null(或者在其他操作系统上重定向到临时文件,参见?tempfile):

sink(file="/dev/null")
f()
sink()

2
sink非常有用。但它也会使函数的返回值失效。 - Sacha Epskamp
1
@Sacha 显而易见的解决方案是将 f() 的输出分配给一个对象。 - Gavin Simpson
6
在一行代码中,执行 capture.output(x <- f()) 的操作。 - hadley

5

这应该可以工作吗?

oldcat = cat
cat = function( ..., file="", sep=" ", fill=F, labels=NULL, append=F ) {}
f()
cat = oldcat

只需将cat替换为空的function,然后在完成后将其设置回来。


3
cat <- function(...) {} 会更简单。 - hadley
甚至可以使用cat <- list,只要cat仅出现在函数中。 - G. Grothendieck
“cat <- list” 看起来有些晦涩。我相信我必须阅读三到四次才能记住我在做什么... - tim_yates
1
rm(cat) 会还原 cat,并删除全局环境中的版本,以便它不会掩盖基础版本。此外,我们可以消除对 oldcat 的需求,因为它始终可以被引用为 base::cat - G. Grothendieck

3
使用invisible()capture.output()可以实现你想要的效果:
f <- function() {
    cat("Hello")
    return(TRUE)
}
f1 <- function() {
    invisible(capture.output(f()))
}
x <- f1()

这也可以工作:

f2 <- function() {
    tmp <- tempfile()
    sink(tmp)
    on.exit(sink())
    on.exit(file.remove(tmp), add = TRUE)
    invisible(force(f())) 
}
x <- f2()

2

这里有一个有趣的技巧,可以注释掉函数中所有的cat()。不确定这样做是否会导致错误或破坏函数:

foo <- deparse(f)
f <- eval(parse(text=gsub("cat","#cat",foo)))

f()

[1] 1

编辑:

另一个选择基本上是Juba的答案,使用sink,但您可以使用Defaults包来更改cat的默认行为。 file参数将其输出沉入文件中。 所以:

library("Defaults")
setDefaults(cat,file="sink.txt")

f()

确保只有cat的输出被接收,而不是print等其他内容。然而,这会极大地降低运行时间,因为现在每次运行cat()时都会打开和关闭文件。


4
天啊!如果你的学生在任何地方使用了单词“cat”,比如一个叫做“catalog”的变量,那么这个想法会毁掉他们的代码! - Spacedman
3
你应该使用正则表达式来解决这个问题:gsub("^cat$", "#cat", foo) - aL3xa
旧的回答。但请注意,这也会在多行“cat”调用中出现问题。 - Oliver

1

purrr库中的quietly()函数可以创建一个安静版本的函数:

library(purrr)
f <- function() {
    cat("Hello")
    return(TRUE)
}
f2 <- quietly(f)
f2()
#> $result
#> [1] TRUE
#> 
#> $output
#> [1] "Hello"
#> 
#> $warnings
#> character(0)
#> 
#> $messages
#> character(0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接