将流系统的输出(连续地)传输到Shiny前端

9
我该如何捕获正在进行的system()操作的输出并将其实时流式传输到Shiny前端?

intern=T可以捕获整个输出为字符向量,但我更希望能够在系统输出发生时“监听”它。
library(shiny) 
ui <- fluidPage(
   titlePanel("Stream the system output"),
   sidebarLayout(
      sidebarPanel(
         actionButton("btn1",label = "Let's stream")
      ),
      mainPanel(
         textOutput("textstream_output")
      )
   )
)
server <- function(input, output, session) {
  rv <- reactiveValues("textstream"=c(""))
  output$textstream_output <- renderText({
    rv$textstream
  })
  observeEvent(input$btn1,{
  # problem: is evaluated after finish, not during operation  
    rv$textstream <- system("Rscript -e \"for(i in 1:5){ print(Sys.time()); Sys.sleep(1);  };\"",
                            intern = T)
  })
}
shinyApp(ui = ui, server = server)

在使用 intern=F 参数运行 system 命令时,R控制台每秒钟会持续更新。我该如何在Shiny中建立这个功能,最好不需要将 system 调用切分成较小的块?

enter image description here

可能相关:

1个回答

6

reactiveTimer 提供了一种方法。我猜测你的方法不起作用是因为 observeEvent 仅在表达式评估完成后更新反应性对象。这是我的方法。我创建一个我想要在后台运行的脚本,so_script.R,并将输出重定向到 so_output.txt。我们希望在脚本运行时查看 so_output.txt 的内容。

cat('sink(file = "so_output.txt")
  for (i in 1:10) {
    cat(format(Sys.time(), format = "%H:%M:%S"), "\n")
    Sys.sleep(1)
  }
  cat("*** EOF ***\n")
  sink()
', file = "so_script.R")

这是Shiny应用程序:

library(shiny) 
ui <- fluidPage(
   titlePanel("Stream the system output"),
   sidebarLayout(
      sidebarPanel(
         actionButton("btn_start",label = "Let's stream"),
         actionButton("btn_stop",label = "Stop")
      ),
      mainPanel(
         htmlOutput("textstream_output")
      )
   )
)
server <- function(input, output, session) {
  rv <- reactiveValues(textstream = c(""),
                       timer = reactiveTimer(1000),
                       started = FALSE)
  observeEvent(input$btn_start, { 
    rv$started <- TRUE
    system2("Rscript", "so_script.R", wait = FALSE)
  })
  observeEvent(input$btn_stop, { rv$started <- FALSE })
  observe({
    rv$timer()
    if (isolate(rv$started))
      rv$textstream <- paste(readLines("so_output.txt"), collapse = "<br/>")
  })
  output$textstream_output <- renderUI({
    HTML(rv$textstream)
  })
}
shinyApp(ui = ui, server = server)

每次计时器触发,如果已经开始流式传输,我们会读取so_output.txt的内容。输出:

enter image description here


嗨,我有点挖掘这篇旧帖子,但它很有帮助。我目前想要实现类似的东西,但是希望从so_output.txt读取停止而不必点击停止按钮。你认为有一种检测方法吗?提前致谢。 - pegot

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