我正在用 Rust 创建一个终端模拟器,目前正在尝试伪终端 (PTY) 并尝试捕获在 PTY 中执行的 shell 命令的输出。但是,我遇到了一个问题:尝试从 PTY 读取输出时程序挂起,并且没有输出打印到终端。
这是我的代码的相关部分:
use portable_pty::{CommandBuilder, PtySize, native_pty_system};
use std::io::Write;
use std::process::Command;
use anyhow::Result;
use anyhow::Error;
pub fn pyt() -> Result<(), Error> {
// Use the native pty implementation for the system
let pty_system = native_pty_system();
// Create a new pty
let mut pair = pty_system.openpty(PtySize {
rows: 24,
cols: 80,
// Not all systems support pixel_width, pixel_height,
// but it is good practice to set it to something
// that matches the size of the selected font. That
// is more complex than can be shown here in this
// brief example though!
pixel_width: 0,
pixel_height: 0,
})?;
// Spawn a shell into the pty
let cmd = CommandBuilder::new("bash");
let child = pair.slave.spawn_command(cmd)?;
// Read and parse output from the pty with reader
let mut reader = pair.master.try_clone_reader()?;
// Send data to the pty by writing to the master
writeln!(pair.master.take_writer()?, "dir\r\n")?;
//output from the pty
let mut output = String::new();
reader.read_to_string(&mut output)?;
println!("output: {}", output);
Ok(())
}
我使用portable_pty crate 来处理PTY 交互。该代码应该是:
但是,当我运行此函数时,它在读取输出时挂起(reader.read_to_string(&mut output)),并且没有任何内容打印到控制台。我不确定为什么它没有捕获 dir 命令的输出或者为什么它挂起。
我尝试过的:
我的问题: 如何正确读取 PTY 的输出而不导致程序挂起? Rust 中是否有特定的技术或方法来异步或非阻塞处理 PTY 输出?
Rust 中的 Streams 默认情况下不使用 Buffer,这需要额外的努力。
查看
reader.read_to_string
文档,该方法会一直读取,直到观察到 EOF
标记为止。因此,冻结是有合理原因的,读者看不到文件结束标记。
cmd 的输出已成功缓冲在您的
output
字符串中,但读者没有线索停止阅读和打印。
根据经验,使用缓冲区来读取和写入 IO。
// ...
// let mut output = String::new();
// reader.read_to_string(&mut output)?;
// println!("output: {}", output);
let mut buf = std::io::BufReader::new(reader);
for line in buf.lines() {
println!("line: {}", line.unwrap());
}
// do not get here
这将逐行打印输出。