尝试在终端仿真器中读取命令输出时,Rust PTY 输出挂起

问题描述 投票:0回答:1

我正在用 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 交互。该代码应该是:

  1. 创建一个新的 PTY。
  2. 在 PTY 中生成 bash shell。
  3. 将命令目录写入 PTY。
  4. 读取并打印 PTY 的输出。

但是,当我运行此函数时,它在读取输出时挂起(reader.read_to_string(&mut output)),并且没有任何内容打印到控制台。我不确定为什么它没有捕获 dir 命令的输出或者为什么它挂起。

我尝试过的:

  • 确保dir命令正确写入PTY。
  • 验证 bash shell 是否在 PTY 中正确生成。

我的问题: 如何正确读取 PTY 的输出而不导致程序挂起? Rust 中是否有特定的技术或方法来异步或非阻塞处理 PTY 输出?

rust tty pty
1个回答
0
投票

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

这将逐行打印输出。

© www.soinside.com 2019 - 2024. All rights reserved.