我正在尝试使用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(使用前将#替换为@)