
1. Command库基础跨平台执行系统命令在Rust中执行系统命令就像让不同国家的翻译帮你传话。std::process::Command就是这位万能翻译它能帮你用Windows的cmd.exe说dir也能用Linux的bash说ls。我刚开始用的时候总纳闷为什么同样的命令在不同平台要换马甲后来才明白这就像中餐在国外要调整口味——系统 shell 就是不同的厨房。先看个基础例子use std::process::Command; let output Command::new(ls) .arg(-l) .output() .expect(命令执行失败); println!({}, String::from_utf8_lossy(output.stdout));这段代码在Linux上能列出详细目录但在Windows会报错。就像你让川菜师傅做寿司他只会给你个问号脸。这时候就需要平台判断let cmd if cfg!(target_os windows) { dir } else { ls -l };关键点Command::new()创建命令构建器.arg()添加参数可链式调用.output()执行并获取结果Windows用反斜杠\Linux用正斜杠/就像中文右引号和英文右引号的区别2. 参数传递的坑与技巧给命令传参数就像教鹦鹉说话——用错语法它就给你错误输出。最坑的是带空格的路径参数直接传会变成两个单词。就像跟外国朋友说红烧 狮子头他可能以为你要烧真狮子。正确姿势// Windows处理带空格路径 Command::new(cmd) .args([/C, type, \C:\\Program Files\\test.txt\]) // Linux更简单 Command::new(sh) .arg(-c) .arg(cat /path with spaces/file.txt)遇到更复杂的参数时我推荐用format!宏let file data.csv; let args format!(awk -F, {{print ${}}} {}, column, file);参数传递对照表场景Windows写法Linux写法多命令串联cmd /C cd dir type filesh -c cd dir cat file带引号参数\value\value环境变量%VAR%$VAR3. 工作目录切换实战切换工作目录就像搬家——东西没搬对地方就会找不到。我踩过的坑是以为切换目录后后续命令都生效结果发现每个Command都是新会话。正确操作// 方法1使用.current_dir() Command::new(git) .current_dir(./project) // 就像cd project .arg(status) // 方法2直接拼接路径适合简单操作 let full_path Path::new(/project/src).join(main.rs);跨平台路径处理建议用std::path::Pathuse std::path::Path; let path Path::new(dir).join(subdir); Command::new(ls) .current_dir(path)常见问题排查路径不存在先用path.exists()检查权限不足Linux下注意chmod相对路径基准相对于当前进程工作目录4. 跨平台构建工具封装实例让我们封装一个实用的构建工具它能自动处理平台差异。就像给不同手机配充电器我们做个万能适配器。use std::process::{Command, Stdio}; use std::path::Path; struct BuildTool { work_dir: String, verbose: bool, } impl BuildTool { fn run(self, cmd: str) - ResultString, String { let (shell, flag) if cfg!(windows) { (cmd.exe, /C) } else { (sh, -c) }; let mut command Command::new(shell); command.arg(flag) .current_dir(self.work_dir); if self.verbose { command.stdout(Stdio::inherit()); } let output command.arg(cmd) .output() .map_err(|e| format!(执行失败: {}, e))?; if output.status.success() { Ok(String::from_utf8_lossy(output.stdout).into_owned()) } else { Err(String::from_utf8_lossy(output.stderr).into_owned()) } } }使用方法let builder BuildTool { work_dir: project.to_string(), verbose: true, }; builder.run(cargo build --release).unwrap();进阶技巧用Stdio::piped()捕获实时输出设置超时控制配合std::thread::spawn环境变量继承控制.env_clear()或.env()5. 错误处理与输出捕获处理命令错误就像看病——要有详细的诊断报告。我早期常犯的错是只看status.code()后来发现stderr才是真正的病历本。完整错误处理示例fn run_safe(cmd: str) - Result(String, String), String { let output Command::new(if cfg!(windows) { cmd } else { sh }) .args(if cfg!(windows) { [/C, cmd] } else { [-c, cmd] }) .output() .map_err(|e| format!(启动失败: {}, e))?; let stdout String::from_utf8_lossy(output.stdout).into_owned(); let stderr String::from_utf8_lossy(output.stderr).into_owned(); if output.status.success() { Ok((stdout, stderr)) } else { Err(format!(命令执行错误: {}\nSTDOUT: {}\nSTDERR: {}, output.status, stdout, stderr)) } }输出处理对照表方法特点适用场景.output()获取全部输出需要完整结果时.spawn()返回Child进程长时间运行进程.status()只获取退出状态简单成功检查6. 高级技巧管道与重定向实现管道就像组装乐高——把多个命令的输出输入连起来。Rust本身不直接支持shell的|符号但我们可以手动连接。模拟管道功能use std::process::{Command, Stdio}; // grep -i hello Cargo.toml | wc -l let grep Command::new(grep) .arg(-i) .arg(hello) .arg(Cargo.toml) .stdout(Stdio::piped()) .spawn()?; let wc Command::new(wc) .arg(-l) .stdin(grep.stdout.unwrap()) // 关键连接前一个命令的输出 .output()?;重定向到文件use std::fs::File; let file File::create(output.log)?; Command::new(cargo) .arg(build) .stdout(file) // 重定向到文件 .status()?;7. 实战自动化部署脚本最后来个真实案例——用Rust写跨平台部署脚本。就像给不同操作系统准备旅行套装既要通用又要考虑个性需求。use std::process::Command; use std::env; fn deploy() - Result(), Boxdyn std::error::Error { let project_dir env::current_dir()?; let build_dir project_dir.join(build); // 清理构建目录 let clean_cmd if cfg!(windows) { format!(rmdir /s /q {}, build_dir.display()) } else { format!(rm -rf {}, build_dir.display()) }; Command::new(if cfg!(windows) { cmd } else { sh }) .args(if cfg!(windows) { [/C, clean_cmd] } else { [-c, clean_cmd] }) .status()?; // 构建项目 let build_status Command::new(cargo) .current_dir(project_dir) .arg(build) .arg(--release) .status()?; if !build_status.success() { return Err(构建失败.into()); } // 部署到服务器示例 if cfg!(target_os linux) { Command::new(scp) .arg(target/release/app) .arg(userserver:/opt/app) .status()?; } Ok(()) }优化建议用tempfilecrate处理临时文件添加进度提示和彩色输出支持dry-run模式用indicatif添加进度条在Windows和Linux双环境下测试时发现路径分隔符和权限问题最常出bug。建议在开发时就用#[cfg(target_os)]做条件编译测试像同时照顾左右撇子用户一样考虑周全。