Ch 26: Command - 进程创建与管理
std::process::Command用于创建和管理外部进程,是Rust中执行系统命令的主要方式。
2. 基本用法
Section titled “2. 基本用法”创建并执行简单命令:
use std::process::Command;
fn main() { // 执行ls命令(Unix)或dir命令(Windows) let output = Command::new("ls") .arg("-la") .output() .expect("执行命令失败");
println!("标准输出: {}", String::from_utf8_lossy(&output.stdout)); println!("标准错误: {}", String::from_utf8_lossy(&output.stderr)); println!("退出码: {}", output.status);}3. 方法签名
Section titled “3. 方法签名”impl Command { pub fn new(program: &str) -> Command
// 参数相关 pub fn arg(&mut self, arg: &str) -> &mut Command pub fn args<I, S>(&mut self, args: I) -> &mut Command where I: IntoIterator<Item = S>, S: AsRef<OsStr>
// 环境相关 pub fn env(&mut self, key: &str, val: &str) -> &mut Command pub fn env_remove(&mut self, key: &str) -> &mut Command pub fn env_clear(&mut self) -> &mut Command
// 目录相关 pub fn current_dir(&mut self, dir: &Path) -> &mut Command
// 执行相关 pub fn output(&mut self) -> Result<Output> pub fn status(&mut self) -> Result<ExitStatus> pub fn spawn(&mut self) -> Result<Child>}4. spawn - 异步执行
Section titled “4. spawn - 异步执行”spawn()创建子进程,不等待其完成:
use std::process::{Command, Stdio};use std::io::Result;
fn main() -> Result<()> { // 启动后台进程 let mut child = Command::new("sleep") .arg("5") .spawn()?;
println!("子进程PID: {}", child.id());
// 等待进程结束 let status = child.wait()?; println!("进程退出码: {:?}", status);
Ok(())}返回的Child结构体:
pub struct Child { pub id: u32, pub stdin: Option<ChildStdin>, pub stdout: Option<ChildStdout>, pub stderr: Option<ChildStderr>,}5. output - 获取输出
Section titled “5. output - 获取输出”output()等待命令完成并返回输出:
use std::process::Command;
fn main() { // 获取命令输出 let output = Command::new("echo") .arg("Hello from Rust!") .output() .expect("执行失败");
assert!(output.status.success()); println!("stdout: {}", String::from_utf8_lossy(&output.stdout));}6. 环境变量配置
Section titled “6. 环境变量配置”use std::process::Command;
fn main() { // 设置环境变量 let output = Command::new("printenv") .arg("HOME") .env("MY_VAR", "custom_value") .output() .expect("执行失败");
println!("{}", String::from_utf8_lossy(&output.stdout));}7. 工作目录
Section titled “7. 工作目录”use std::process::Command;use std::path::Path;
fn main() { // 指定工作目录 let output = Command::new("pwd") .current_dir("/tmp") .output() .expect("执行失败");
println!("{}", String::from_utf8_lossy(&output.stdout));}8. 输入输出重定向
Section titled “8. 输入输出重定向”use std::process::{Command, Stdio};use std::fs::File;
fn main() { // 从文件读取输入 let input = File::open("input.txt").unwrap(); let output = Command::new("grep") .arg("pattern") .stdin(Stdio::from(input)) .output() .expect("执行失败");
// 输出到文件 let mut file = File::create("output.txt").unwrap(); Command::new("ls") .stdout(Stdio::from(file)) .spawn() .expect("执行失败");}Stdio变体:
pub enum Stdio { Inherited, // 继承父进程 Piped, // 管道 Null, // /dev/null FromRaw(FileDesc), // 从文件描述符创建}9. uid和用户身份(Unix)
Section titled “9. uid和用户身份(Unix)”use std::process::Command;
fn main() { #[cfg(unix)] { // 以root身份运行 let output = Command::new("ls") .arg("/root") .uid(0) // root UID .spawn() .expect("需要root权限"); }}方法签名(Unix):
pub fn uid(&mut self, id: u32) -> &mut Commandpub fn gid(&mut self, id: u32) -> &mut Command10. 注意事项
Section titled “10. 注意事项”- 安全性:避免将未过滤的用户输入作为命令参数
- 错误处理:检查
Result和status,子进程可能启动失败 - 僵尸进程:使用
wait()确保子进程被回收 - shell注入:优先使用
arg()而非通过shell执行复杂命令
11. 总结
Section titled “11. 总结”Command是Rust中执行外部程序的核心API:
new()- 创建命令arg()/args()- 添加参数spawn()- 异步启动output()- 同步执行并获取输出status()- 同步执行并获取退出码
配合环境变量、目录和输入输出重定向,可以构建复杂的进程交互逻辑。