从 R 中的系统调用捕获退出状态和输出

Posted

技术标签:

【中文标题】从 R 中的系统调用捕获退出状态和输出【英文标题】:Capture both exit status and output from a system call in R 【发布时间】:2011-10-24 06:03:41 【问题描述】:

我一直在玩system()system2() 来取乐,令我震惊的是我可以将输出或退出状态保存在一个对象中。一个玩具例子:

X <- system("ping google.com",intern=TRUE)

给我输出,而

X <- system2("ping", "google.com")

给我退出状态(在这种情况下为 1,谷歌不接受 ping)。如果我想要输出和退出状态,我必须进行 2 次系统调用,这似乎有点矫枉过正。仅使用一个系统调用如何实现两者?

编辑:如果可能的话,我希望将两者都放在控制台中,而无需在 system2 调用中使用 stdout="somefile.ext" 并随后将其读入。

【问题讨论】:

您使用的是 Linux 还是 Windows?我什至无法让 stdout="somefile.ext" 在 Windows 上运行,但它在 Linux 上运行良好...... 我建议将linux 与您使用的任何外壳一起添加到您的标签中。这可以邀请操作系统专家的一些解决方案。 向 OP 和 @Gavin 道歉,我可能弄错了:我认为这是明确或隐含的 Linux,但我看到 OP 甚至没有提到 Linux,据我所知,它可能是另一个操作系统. 它不是 Linux,甚至不是特定于操作系统的。这是关于 R 代码的。 【参考方案1】:

从 R 2.15 开始,system2 将在 stdout 和/或 stderr 为 TRUE 时将返回值作为属性提供。这使得获取文本输出和返回值变得容易。

在这个例子中,ret 最终是一个带有属性"status" 的字符串:

> ret <- system2("ls","xx", stdout=TRUE, stderr=TRUE)
Warning message:
running command ''ls' xx 2>&1' had status 1 
> ret
[1] "ls: xx: No such file or directory"
attr(,"status")
[1] 1
> attr(ret, "status")
[1] 1

【讨论】:

【参考方案2】:

我对你对 system2 的描述有点困惑,因为它有 stdout 和 stderr 参数。所以它能够返回退出状态,stdout 和 stderr。

> out <- tryCatch(ex <- system2("ls","xx", stdout=TRUE, stderr=TRUE), warning=function(w)w)
> out
<simpleWarning: running command ''ls' xx 2>&1' had status 2>
> ex
[1] "ls: cannot access xx: No such file or directory"
> out <- tryCatch(ex <- system2("ls","-l", stdout=TRUE, stderr=TRUE), warning=function(w)w)
> out
 [listing snipped]                  
> ex
 [listing snipped]

【讨论】:

+1 非常好。顺便说一句,欢迎来到 SO,不是每个人都会阅读 R 命令的帮助信息。 ;-) +1,因为它使用了 R 的内部警告和错误技巧。我可以从警告消息中删除退出状态。我知道我可以使用 stdout=TRUE,但退出状态是我主要关心的问题。这就是我没有这样做的原因。 似乎无论如何都是这样做的,所以这将是公认的答案。 当我运行第一个命令 (ls xx) 时,我收到了与 out 相同的警告消息,但根本没有设置 ex。这适用于 Mac 和 Linux 上的 R 2.14.2。有没有其他方法可以做到这一点?【参考方案3】:

我建议在这里使用这个功能:

robust.system <- function (cmd) 
  stderrFile = tempfile(pattern="R_robust.system_stderr", fileext=as.character(Sys.getpid()))
  stdoutFile = tempfile(pattern="R_robust.system_stdout", fileext=as.character(Sys.getpid()))

  retval = list()
  retval$exitStatus = system(paste0(cmd, " 2> ", shQuote(stderrFile), " > ", shQuote(stdoutFile)))
  retval$stdout = readLines(stdoutFile)
  retval$stderr = readLines(stderrFile)

  unlink(c(stdoutFile, stderrFile))
  return(retval)

这仅适用于接受 > 和 2> 符号的类 Unix shell,并且 cmd 参数不应重定向输出本身。但它确实有效:

> robust.system("ls -la")
$exitStatus
[1] 0

$stdout
 [1] "total 160"                                                      
 [2] "drwxr-xr-x  14 asieira  staff    476 10 Jun 18:18 ."            
 [3] "drwxr-xr-x  12 asieira  staff    408  9 Jun 20:13 .."           
 [4] "-rw-r--r--   1 asieira  staff   6736  5 Jun 19:32 .Rapp.history"
 [5] "-rw-r--r--   1 asieira  staff  19109 11 Jun 20:44 .Rhistory"    

$stderr
character(0)

【讨论】:

谢谢,这很好用!这确实应该是 R 中的默认功能。

以上是关于从 R 中的系统调用捕获退出状态和输出的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Racket 中返回系统命令的退出状态和输出?

Linux 内核进程管理 ( 进程状态 | 进程创建 | 进程终止 | 调用 exit 系统调用函数主动退出 | main 函数返回自动退出 | kill 杀死进程 | 执行异常退出 )

如何在 Perl 中捕获输出和退出代码时执行外部脚本?

python 调用系统命令 获取结束状态

捕获和处理来自 R 的外部命令的输出

Windows 消息 - 捕获来自另一个 API 的调用