在Rust中执行命令:如何捕获输出(2025版)

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

从Python到Rust:命令执行的演进

\n\n

如果你曾在Stack Overflow上问过“如何调用系统命令并捕获其输出?”,你就会知道:这是任何开发者最常遇到且至关重要的问题之一。在Python世界里,答案很简单——subprocess.check_output()。但如果你转向了Rust,并且不仅想运行命令,还想优雅、安全且以最高性能地完成它,该怎么办?

\n\n

Rust不仅仅是“另一种语言”。它是一个每个字节都在掌控之中、命令执行错误不会导致整个应用程序崩溃的系统。在2025年,当安全性和速度已成为事实标准时,正确使用Rust子进程是一项必备技能。让我们来剖析最佳实践,将系统命令的启动从例行公事转变为一种艺术。

\n\n

std::process::Command:你的瑞士军刀

\n\n

Rust中命令执行的核心是std::process::Command模块。它提供了启动外部程序、捕获其输出以及处理错误所需的一切。与Python中subprocess隐藏了许多细节不同,Rust赋予你完全的控制权。

\n\n

基础示例:捕获stdout

\n\n

我们从经典开始——执行命令echo "Hello, Rust!"并捕获其输出:

\n\n
use std::process::Command;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let output = Command::new("echo")\n        .arg("Hello, Rust!")\n        .output()?;\n\n    let stdout = String::from_utf8(output.stdout)?;\n    println!("命令输出: {}", stdout);\n\n    Ok(())\n}\n
\n\n

这里重要的是什么?我们使用了.output(),它返回一个Output结构体。该结构体包含三个字段:stdout、stderr和status。请注意?——这是错误传播运算符,它使我们免于编写冗长的match块。Rust强制我们显式处理可能的故障:命令可能不存在、没有访问权限或直接以错误结束。

\n\n

处理stderr和返回码

\n\n

在实际场景中,你不仅需要stdout,还需要stderr。想象一下,你运行ls /nonexistent——一个肯定会报错的命令:

\n\n
use std::process::Command;\n\nfn main() {\n    let output = Command::new("ls")\n        .arg("/nonexistent")\n        .output()\n        .expect("无法执行命令");\n\n    if output.status.success() {\n        let stdout = String::from_utf8_lossy(&output.stdout);\n        println!("成功: {}", stdout);\n    } else {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        eprintln!("错误 (代码 {}): {}", output.status.code().unwrap_or(-1), stderr);\n    }\n}\n
\n\n

这里我们使用了String::from_utf8_lossy()——一种将字节安全转换为字符串的方法,它会将无效的UTF-8字符替换为�。如果命令输出包含二进制数据或使用不可预测的编码,这一点至关重要。

\n\n

进阶技术:异步与管道

\n\n

在2025年,同步执行命令已经过时了。现代应用程序需要异步性,尤其是在处理Web服务器或同时处理多个命令时。Rust及其Tokio生态系统提供了优雅的解决方案。

\n\n

使用Tokio异步捕获输出

\n\n

在Cargo.toml中添加依赖:

\n\n
[dependencies]\ntokio = { version = "1", features = ["full"] }\n
\n\n

现在异步执行命令:

\n\n
use tokio::process::Command;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let output = Command::new("sleep")\n        .arg("2")\n        .output()\n                

博客

书籍推荐