Одновременно сохранять и распечатывать выходные данные системного вызова R? - PullRequest
1 голос
/ 14 июля 2020

В моем сценарии R я вызываю сценарий оболочки. Я хотел бы как выводить вывод на консоль в реальном времени, так и сохранять вывод для отладки. Например:

system("script.sh")

выводит на консоль в реальном времени,

out <- system("script.sh", intern = TRUE)

сохраняет вывод в переменную для отладки, а

(out <- system("script.sh", intern = TRUE))

печатает только содержимое out после завершения сценария. Есть ли способ как печатать на консоль в реальном времени, так и сохранять вывод как переменную?

1 Ответ

3 голосов
/ 14 июля 2020

Так как R в любом случае ожидает завершения этого процесса, обычно, чтобы увидеть стандартный вывод в реальном времени , вам необходимо опросить процесс для вывода. (Можно / нужно также опросить stderr, в зависимости.)

Вот быстрый пример с использованием processx.

Сначала я создам медленный вывод сценарий оболочки; замените это на настоящую причину, по которой вы звоните system. Я назвал это myscript.sh.

#!/bin/bash
for i in `seq 1 5` ; do
  sleep 3
  echo 'hello world: '$i
done

Теперь давайте (1) запустим процесс в фоновом режиме, затем (2) будем опрашивать его вывод каждую секунду.


proc <- processx::process$new("bash", c("-c", "./myscript.sh"), stdout = "|")
output <- character(0)
while (proc$is_alive()) {
  Sys.sleep(1)
  now <- Sys.time()
  tmstmp <- sprintf("# [%s]", format(now, format = "%T"))
  thisout <- proc$read_output_lines()
  if (length(thisout)) {
    output <- c(output, thisout)
    message(tmstmp, " New output!\n", paste("#>", thisout))
  } else message(tmstmp)
}
# [13:09:29]
# [13:09:30]
# [13:09:31]
# [13:09:32]New output!
#> hello world: 1
# [13:09:33]
# [13:09:34]
# [13:09:35]New output!
#> hello world: 2
# [13:09:36]
# [13:09:37]
# [13:09:38]New output!
#> hello world: 3
# [13:09:39]
# [13:09:40]
# [13:09:41]New output!
#> hello world: 4
# [13:09:42]
# [13:09:43]
# [13:09:44]New output!
#> hello world: 5

И его вывод сохраняется:

output
# [1] "hello world: 1" "hello world: 2" "hello world: 3" "hello world: 4" "hello world: 5"

Способы расширения:

  1. Добавляйте / сохраняйте временную метку с каждым сообщением, чтобы вы знали, когда оно пришло. Точность и полезность этого зависит от того, как часто вы хотите, чтобы R опрашивал конвейер stdout процесса, и действительно, сколько вам нужно этой информации.

  2. Запустить процесс в фоновом режиме и даже опросить его в фоновых циклах. Я использую пакет later и настраиваю самовоспроизводящуюся функцию, которая опрашивает, добавляет и повторно отправляет себя в очередь процесса later. Преимущество этого состоит в том, что вы можете продолжать использовать R; недостатком является то, что если вы запускаете длинный код, вы не увидите вывода, пока ваш текущий код не выйдет и не позволит R дышать и делать что-то праздно. (Чтобы понять эту пулю, действительно нужно поиграть с пакетом later, что немного выходит за рамки этого ответа.)

  3. В зависимости от ваших намерений может быть более подходящим, чтобы вывод был go в файл и «навсегда» сохранить его там, вместо того, чтобы полагаться на процесс R для отслеживания вкладок. У этого есть недостатки, так как теперь вам нужно управлять опросом файла на предмет изменений, а R не делает это простым (например, у него нет прямого / легкого доступа к inotify, поэтому теперь он получает даже посложнее).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...