【问题标题】:How would you stream output from a Process?您将如何流式传输流程的输出?
【发布时间】:2015-11-06 15:46:57
【问题描述】:

我相信我一般理解这样做的一种方式:

  • 创建Command
  • 使用Stdio::piped() 创建一对新的输出流
  • 配置command.stdout()command.stderr()
  • 产生进程
  • 创建一个新线程并将标准错误和标准输出传递给它
  • 在远程线程中,不断轮询输入并将其写入输出流。
  • 在主线程中,等待进程完成。

听起来对吗?

我的两个实际问题:

  1. 有没有更简单的方法不涉及每个进程的“读取线程”?

  2. 如果没有更简单的方法,Read::read() 需要 &mut self;你如何将它传递给远程线程?

请提供具体示例说明如何实际流式传输输出,而不仅仅是关于如何做的一般性建议...

更具体地说,这里是the default example of using spawn

use std::process::Command;

let mut child = Command::new("/bin/cat")
                        .arg("file.txt")
                        .spawn()
                        .expect("failed to execute child");

let ecode = child.wait()
                 .expect("failed to wait on child");

assert!(ecode.success());

如何更改上面的示例以将 child 的输出流式传输到控制台,而不仅仅是等待退出代码?

【问题讨论】:

  • 在一般情况下,为了给对话提供一个起点,最好让 OP(你)提供尽可能少的代码示例来展示问题,然后询问如何解决说问题。例如,您可以将“这样做的一种方式”转换为代码示例。
  • 我很乐意接受任何生成长时间运行的进程并将输出流式传输到控制台的示例,无论以何种方式。

标签: rust


【解决方案1】:

虽然接受的答案是正确的,但它并没有涵盖非平凡的情况。

要流式输出并手动处理,请使用Stdio::piped() 并手动处理调用spawn 返回的子级的.stdout 属性,如下所示:

use std::process::{Command, Stdio};
use std::path::Path;
use std::io::{BufReader, BufRead};

pub fn exec_stream<P: AsRef<Path>>(binary: P, args: Vec<&'static str>) {
    let mut cmd = Command::new(binary.as_ref())
        .args(&args)
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();

    {
        let stdout = cmd.stdout.as_mut().unwrap();
        let stdout_reader = BufReader::new(stdout);
        let stdout_lines = stdout_reader.lines();

        for line in stdout_lines {
            println!("Read: {:?}", line);
        }
    }

    cmd.wait().unwrap();
}

#[test]
fn test_long_running_process() {
    exec_stream("findstr", vec!("/s", "sql", "C:\\tmp\\*"));
}

另请参阅Merge child process stdout and stderr,了解同时捕获 stderr 和 stdout 的输出。

【讨论】:

  • 这个答案很有用!快速提问:有什么特殊原因将流读取部分放在单独的范围内?
  • @PascalPrecht 将cmd 的可变借用分开,首先是stdout,其次是cmd.wait()。今天编译器会在cmd.wait() 语句之前自动删除stdout,但我认为过去并非如此。所以需要这里的作用域来限制stdout的生命周期。
【解决方案2】:

我很乐意接受任何生成长时间运行的进程并将输出流式传输到控制台的示例,无论以何种方式。

听起来你想要Stdio::inherit

use std::process::{Command, Stdio};

fn main() {
    let mut cmd =
        Command::new("cat")
        .args(&["/usr/share/dict/web2"])
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .spawn()
        .unwrap();

    // It's streaming here

    let status = cmd.wait();
    println!("Exited with status {:?}", status);
}

【讨论】:

  • 这实际上与默认行为不同吗?
  • @msgmaxim 您可以检查documentation for Command::new 以查看默认值:spawnstatus 继承stdin/stdout/stderr,但为output 创建管道。 TL;DR:不,我不这么认为。有时只是过于明确或将文档读回 OP 就可以了。请注意原始问题上要求 MCVE 的 cmets,试图让 OP 进一步解释问题。 ¯\_(ツ)_/¯
  • 让我免于在调试上浪费更多时间。谢谢!这是如何将 stdout/stderr 流式传输到控制台以及正确地将 stdin 问题冒泡给用户的简单解决方案。
猜你喜欢
  • 2017-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
相关资源
最近更新 更多