You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust自定义终端命令执行成功但无回显,如何解决?

问题

现有一段Rust代码,用于在终端中通过按键触发自定义Shell命令,每个命令包含触发键、描述和实际执行的Shell命令。代码可正常执行,但Shell命令的输出未在终端回显,仅显示执行成功提示。

代码如下:

use std::io::{stdin, stdout, Write};
use std::process::Command;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;

struct CustomCommand {
    key: char,
    description: &'static str,
    shell_command: &'static str,
}

impl CustomCommand {
    fn execute_shell_command(&self) {
        let output = Command::new("sh")
            .arg("-c")
            .arg(self.shell_command)
            .output();

        match output {
            Ok(output) => {
                if output.status.success() {
                    println!("Command executed successfully\r\n");
                } else {
                    println!("Command execution failed\r\n");
                }
            }
            Err(e) => {
                println!("Error executing command: {:?}\r\n", e);
            }
        }
    }
}

fn main() {
    // 开启终端原始模式
    let mut stdout = stdout().into_raw_mode().unwrap();

    // 定义可用命令
    let commands = vec![CustomCommand {
        key: 'c',
        description: "This is a custom command",
        shell_command: "echo 'Custom command executed'",
    }];

    // 向终端打印提示信息
    write!(stdout, "Please select a command:\r\n").unwrap();

    // 为用户列出自定义命令
    for command in &commands {
        write!(stdout, "{}  {}\r\n", command.key, command.description).unwrap();
    }

    stdout.flush().unwrap();

    // 从标准输入读取输入
    let input = stdin().keys();

    // 遍历按下的每个按键
    for key in input {
        // 将按键与可用命令匹配
        match key.unwrap() {
            // 如果按键匹配命令,执行并退出循环
            Key::Char(k) if commands.iter().any(|c| c.key == k) => {
                let command = commands.iter().find(|c| c.key == k).unwrap();
                command.execute_shell_command();
                break;
            }
            // 输出其他字符
            Key::Char(c) => {
                write!(stdout, "You pressed: {}\r\n", c).unwrap();
                stdout.flush().unwrap();
            }
            // 忽略其他按键
            _ => {}
        }
    }
}

当前执行后的终端输出:

Please select a command:
c  This is a custom command
Command executed successfully
alex@alex-M52AD-M12AD-A-F-K31AD:~/rust/cc$ 
原因分析

核心问题在于使用了Command::output()方法:

  • 该方法会捕获子进程的标准输出(stdout)和标准错误(stderr),将其存储在返回的Output结构体中,不会直接输出到终端。
  • 现有代码仅判断了命令执行的成功状态,未将捕获到的子进程输出内容打印到终端。
  • 终端处于raw模式虽不是输出不回显的直接原因,但后续恢复终端模式能避免终端后续行为异常。
修复方案

提供两种可行的修复方式,可根据需求选择:

方式一:让子进程直接继承终端的IO(推荐)

如果不需要捕获子进程的输出,只是想让命令直接在终端执行并显示输出,可改用Command::status()方法,并配置子进程继承当前进程的标准输入、输出和错误流。

修改execute_shell_command函数如下:

fn execute_shell_command(&self) {
    let status = Command::new("sh")
        .arg("-c")
        .arg(self.shell_command)
        // 让子进程继承当前终端的stdin/stdout/stderr
        .stdin(std::process::Stdio::inherit())
        .stdout(std::process::Stdio::inherit())
        .stderr(std::process::Stdio::inherit())
        .status();

    match status {
        Ok(status) => {
            if status.success() {
                println!("\r\nCommand executed successfully\r\n");
            } else {
                println!("\r\nCommand execution failed\r\n");
            }
        }
        Err(e) => {
            println!("\r\nError executing command: {:?}\r\n", e);
        }
    }
}

同时在main函数结束前添加终端模式恢复代码(RawTerminal的Drop会自动恢复模式,显式处理更稳妥):

// 恢复终端正常模式
drop(stdout);

方式二:捕获子进程输出并手动打印

如果需要对输出进行处理后再显示,可继续使用output()方法,将捕获到的stdout和stderr内容转换为字符串并打印。

修改execute_shell_command函数如下:

fn execute_shell_command(&self) {
    let output = Command::new("sh")
        .arg("-c")
        .arg(self.shell_command)
        .output();

    match output {
        Ok(output) => {
            // 打印子进程的标准输出
            if let Ok(stdout_str) = String::from_utf8(output.stdout) {
                print!("{}", stdout_str);
            }
            // 打印子进程的标准错误
            if let Ok(stderr_str) = String::from_utf8(output.stderr) {
                eprint!("{}", stderr_str);
            }
            
            if output.status.success() {
                println!("\r\nCommand executed successfully\r\n");
            } else {
                println!("\r\nCommand execution failed\r\n");
            }
        }
        Err(e) => {
            println!("Error executing command: {:?}\r\n", e);
        }
    }
}

同样建议在main函数末尾添加drop(stdout)来恢复终端正常模式。

内容的提问来源于stack exchange,提问作者wyc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:52:57