Как захватить вывод системы()

Этот вопрос был мотивирован Rmarkdown, не выводя результаты системной команды в html файл. По какой-то причине вывод system() в R (или system2()) не может быть зафиксирован с помощью sink() или capture.output(), поэтому в настоящее время нет возможности для knitr записывать вывод. Например, в консоли R:

> system('ls')
DESCRIPTION
NAMESPACE
R
README.md
inst
man

но в документе knitr вы не увидите результат, потому что capture.output(system('ls')) - character(0), то есть вывод не может быть захвачен. Конечно, я могу сделать cat(system('ls', intern = TRUE), sep = '\n'), как я упомянул в ответе на этот вопрос, но это неловко. Интересно, является ли это способом захвата вывода system() без использования intern = TRUE и cat().


Обновить: см. https://github.com/yihui/knitr/issues/1203 для взлома, который я предоставил для решения проблемы.

Ответы

Ответ 1

Вы можете добавить функцию knitr::system, которая маскирует base::system. Пользователи могли работать с ним, как будто это было system::base, но вывод можно записать с помощью capture.output:

system <- function(...) {
  stopifnot(!any(names(list(...)) %in% "intern"))
  result <- base::system(..., intern = TRUE)
  print(result)
}

Я признаю, что это несколько хакерский, и, честно говоря, я не уверен в возможных побочных эффектах. Но я думаю, что стоит попробовать.

Ответ 2

Я не думаю, что вы можете это сделать (по крайней мере, на системах * nix, у меня нет операционной системы Windows/Mac), потому что system, как представляется, незримо возвращает значение, возвращаемое командой, и R не перенаправляет вывод команды в консоль R.

Это связано с тем, что stdout вашего терминала не совпадает с консолью R stdout. То, что вы видите из своей сессии R, - это соединение терминала stdout и выходного процесса R. capture.output ищет выход процесса R, не все выводятся в stdout из родительского процесса.

Вы можете запустить процесс, который печатает на stdout, поместить его в фоновом режиме, а затем запустить R... и вы увидите, что этот процесс будет выводиться в вашем "R-выходе", как если бы вы выполнили system("ping -c5 8.8.8.8") от R.

[email protected]: /home/josh
> ping -c5 8.8.8.8 & R
[1] 5808
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=46 time=39.9 ms

R version 3.2.4 Revised (2016-03-16 r70336) -- "Very Secure Dishes"
Copyright (C) 2016 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> 64 bytes from 8.8.8.8: icmp_seq=2 ttl=46 time=38.1 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=46 time=38.3 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=46 time=38.4 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=46 time=38.3 ms

--- 8.8.8.8 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4003ms
rtt min/avg/max/mdev = 38.176/38.656/39.986/0.703 ms

> q()
Save workspace image? [y/n/c]: n
[1]+  Done                    ping -c5 8.8.8.8

[email protected]: /home/josh
>