运行命令、流式传输 stdout/stderr 并捕获结果

2023-12-06

我正在尝试使用std::process::Command运行命令并流式传输其 stdout 和 stderr,同时捕获 stdout/stderr 的副本。我发现我可以使用spawn.

此代码将捕获输出,但不会在发生时将其流式传输到 stdout/stderr:

let mut child = command
    .envs(env)
    .stdout(Stdio::piped()) // <=== Difference here
    .spawn()
    .unwrap();

let output = child
    .wait_with_output().unwrap();

println!("Done {}", std::str::from_utf8(&output.stdout).unwrap());

此代码将流式传输输出但不捕获它:

let mut child = command
    .envs(env)
    .spawn()
    .unwrap();

let output = child
    .wait_with_output().unwrap();

println!("Done {}", std::str::from_utf8(&output.stdout).unwrap());

有没有办法捕获命令的输出,同时将其流式传输到父级 stdout/stderr?


可能有一种不太冗长的方法来做到这一点,但这是我想出的解决方案。

使用 stdout 和 stderr 的管道 io 生成进程。为 stdout 和 stderr 生成一个线程。在每个线程中从管道读取并直接输出到 stdout 或 stderr,然后将内容写入通道。

在主线程中等待进程完成,然后加入线程,最后读取每个通道以获取stdout和stderr的内容。

use std::io::BufRead;

let mut child = command
    .stdout(Stdio::piped())
    .stderr(Stdio::piped())
    .spawn()
    .unwrap();

let child_stdout = child
    .stdout
    .take()
    .expect("Internal error, could not take stdout");
let child_stderr = child
    .stderr
    .take()
    .expect("Internal error, could not take stderr");

let (stdout_tx, stdout_rx) = std::sync::mpsc::channel();
let (stderr_tx, stderr_rx) = std::sync::mpsc::channel();

let stdout_thread = thread::spawn(move || {
    let stdout_lines = BufReader::new(child_stdout).lines();
    for line in stdout_lines {
        let line = line.unwrap();
        println!("{}", line);
        stdout_tx.send(line).unwrap();
    }
});

let stderr_thread = thread::spawn(move || {
    let stderr_lines = BufReader::new(child_stderr).lines();
    for line in stderr_lines {
        let line = line.unwrap();
        eprintln!("{}", line);
        stderr_tx.send(line).unwrap();
    }
});

let status = child
    .wait()
    .expect("Internal error, failed to wait on child");

stdout_thread.join().unwrap();
stderr_thread.join().unwrap();

let stdout = stdout_rx.into_iter().collect::<Vec<String>>().join("");
let stderr = stderr_rx.into_iter().collect::<Vec<String>>().join("");

该通道并不是严格需要的。我原本想改变一个字符串,但我是 Rust 的线程新手,找不到任何示例来展示如何在线程中改变字符串,然后将其读回到 main 中。

我接受其他解决方案,因为它确实回答了我的主要问题。我只是想回帖给大家一个功能齐全的答案,完全符合我最初的要求

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

运行命令、流式传输 stdout/stderr 并捕获结果 的相关文章

随机推荐

  • 提取矩阵的对角线(非对角线)元素

    可能这个问题太简单了 但我找不到实用的答案 我们如何提取R中任意方阵的相反对角线元素 在下面的示例中 将是 7 2 8 r lt matrix c 1 5 8 1 3 7 9 3 一种方法可能是 r n lt nrow r 2 1 n n
  • 如何在不使用其他寄存器的情况下镜像一个字节?

    假设我在 AL 中有这个字节 01100001申请后mirror函数我想要的字节是10000110 我提出的所有想法都必须使用其他寄存器 但我很好奇是否有一种方法可以在不使用任何其他寄存器的情况下镜像字节 代码中立即存储 变体 mirror
  • 如何将 minOccurs 设置为 1

    我正在构建 ASP NET Web 服务 我的代码定义如下 但我不知道如何使用 wsdl 指定 FirstName 和 LastName 属性的 minOccurs 我想要那些需要的 并且不能为空 是否可以 WebMethod public
  • 我可以更改 Android 设备的 LED 强度吗?

    有没有办法设置我想要的 LED 强度 我知道要打开 LED 我使用 p setFlashMode Camera Parameters FLASH MODE TORCH mycam setParameters p 但这段代码只是打开 LED
  • 使用 Python 和 lxml 根据外部 DTD 验证 XML

    我正在尝试根据 doctype 标记中引用的外部 DTD 验证 XML 文件 具体来说 the rest of the document 我正在使用 Python 3 3 和 lxml 模块 来自阅读http lxml de validat
  • 当“Model”实例是在启用急切模式的情况下构造的时,不支持在图形模式下调用“Model.predict”

    所以我只是跟随某人的项目并在收到此错误时到达这里 2020 10 12 15 33 21 128 ERROR in app Exception on predict POST Traceback most recent call last
  • 无法更改网状中的Python路径

    启动 rstudio 会话时运行的第一行是 library reticulate use python usr local lib python3 6 site packages 然而 当我跑步时py config 它显示仍在使用默认的 p
  • 使用 Objective C 将文本字符串插入 NSTextView 中的光标位置或选择的文本

    我如何使用 Objective C 和 cocoa 使用 Xcode 来做到这一点 我试图在单击按钮时在光标处或用户选择处插入一个字符串 NSTextView 有一个方法 insertText 可以执行您想要的操作 myTextView i
  • 使用 PyQt 动态将项目设置为 QML ListModel

    我有一个代表时间表的 QML 它从数据库获取值 所以我需要插入值ListModel来自我的Python代码 QML 看起来像这样 function append newElement scheduleList model append ne
  • 如何在正则表达式中定义空格(在 awk 中)?

    我想打印里面的文字 例如我有以下字符串 gfdg jkfgh jkfd fdgj fd ghjhgj gfggf kfdjfdgfhbg fhfghg jhgj jhfjhg dfgdf fgf fgfdg dfj jfdg jhfgjd
  • 如何使用Kivy制作ToolTip?

    我想看到工具提示Qt当鼠标指针悬停在图标上时操作栏 是的 我可以使用mode spinner 但图标更好 您可以改进和扩展的一个简单示例 from kivy app import App from kivy lang import Buil
  • 将进程 ID 添加到 log4cxx 中的日志文件名中

    在 log4net 中 我可以轻松地将进程 ID 设置为从配置中轻松记录文件名
  • 无循环求和

    I have following double summation 10 i 1 i j 1 i 5 10 j i 我对这个练习很迷茫 我尝试了下面的代码 但尽管给了我一个数字 但它返回了一个错误 很确定它不正确 任何帮助都非常有价值 i
  • 如何获取 Facebook 视频的观看次数

    我首先使用 facebook graph api 获取全局视频视图 然后我想尝试单独的视频视图 但是当我尝试以下语法时 获取 v2 5 object id insights page video views 我得到这个答案 data pag
  • 用于命名空间扩展的图标覆盖处理程序

    我正在开发命名空间扩展 它提供服务器上文件的虚拟视图 在此视图中 我需要使用覆盖图标提供文件的不同状态 正在使用 离线 不同步等 我阅读了实现覆盖处理程序的文章 并认为我将尝试在我们的覆盖处理程序之一中处理此问题 该处理程序实现 IShel
  • 如何使用Cookie检查用户是否已经登录?

    我想知道如何检测用户是否已经登录 使用cookie 我没有使用任何登录控件 我有一个数据库可以检查 ID 和 PWD 另请告诉我是否可以在不使用 cookie 的情况下完成 任何代码或链接都会有帮助 网络配置
  • Android 下拉颜色选择器

    我想创建一个下拉颜色选择器 如下所示 抱歉图像丑陋 我只需要一些颜色 比方说 6 种 所以我不需要完整的颜色选择器 下拉菜单就可以正常工作 我知道我必须扩展 Spinner 的阵列适配器并覆盖获取下拉视图 and getView 我不知道的
  • 如何从一个文件中读取随机行?

    有内置方法可以做到这一点吗 如果不是 我怎样才能在不花费太多开销的情况下做到这一点 不是内置的 而是算法R 3 4 2 Waterman 的 Reservoir Algorithm 来自 Knuth 的 计算机编程的艺术 很好 非常简化的版
  • 如何从父子表中获取结果

    Work on SQL服务器 我的表结构如下 CREATE TABLE dbo AgentInfo AgentID int NOT NULL ParentID int NULL CONSTRAINT PK AgentInfo PRIMARY
  • 运行命令、流式传输 stdout/stderr 并捕获结果

    我正在尝试使用std process Command运行命令并流式传输其 stdout 和 stderr 同时捕获 stdout stderr 的副本 我发现我可以使用spawn 此代码将捕获输出 但不会在发生时将其流式传输到 stdout