一、核心概念速查
Command 的三种「执行」方法
| 方法 |
返回类型 |
何时用 |
典型场景 |
.output() |
Result<Output, io::Error> |
只关心最终结果,一次性跑完拿输出 |
run_command |
.spawn() |
Result<Child, io::Error> |
需要边跑边交互(双向通信) |
pipe_through_* |
.status() |
Result<ExitStatus, io::Error> |
只关心退出码,不关心输出 |
get_exit_code |
Command 的配置方法
| 方法 |
作用 |
Command::new(program) |
指定要启动的程序 |
.arg(x) |
加一个参数 |
.args(iter) |
加一堆参数(接受数组/切片/Vec) |
.stdinpiped() |
接管子进程输入,接管道 |
.stdoutpiped() |
接管子进程输出,接管道 |
错误处理三件套
| 写法 |
成功 |
失败 |
适用条件 |
.unwrap() |
取出值 |
panic 崩溃 |
函数不返回 Result |
.expect("msg") |
取出值 |
panic + 自定义信息 |
函数不返回 Result |
? |
取出值 |
提前 return Err |
函数必须返回 Result |
处理 Option 的两种方式
| 写法 |
Some(x) |
None |
.unwrap() |
取出 x |
panic |
.unwrap_or(默认值) |
取出 x |
返回默认值 |
二、两种「模式」
模式 A:执行并拿结果(单向)
Command::new(程序) → .args(参数) → .output()/.status() → 处理结果
用于:run_command、get_exit_code、run_command_with_result
模式 B:双向管道通信
spawn → take stdin → write_all → drop(stdin) → take stdout → read_to_string → wait
用于:pipe_through_cat、pipe_through_grep
三、5 个函数对照表
| 函数 |
模式 |
关键方法 |
新知识点 |
run_command |
A |
.output() |
String::from_utf8 + unwrap |
pipe_through_cat |
B |
.spawn() + .take() + drop |
双向管道全流程 |
get_exit_code |
A |
.status() + .code() |
sh -c 技巧、unwrap_or |
run_command_with_result |
A |
.output()? |
? 运算符、map_err |
pipe_through_grep |
B |
同 cat,多 .arg(pattern) |
模式 B 复用 |
四、完整代码合集(可直接对照)
1. run_command
pub fn run_command(program: &str, args: &[&str]) -> String {
let output = Command::new(program)
.args(args)
.stdoutpiped()
.output()
.expect("Failed to execute command");
String::from_utf8(output.stdout).unwrap()
}
2. pipe_through_cat
pub fn pipe_through_cat(input: &str) -> String {
let mut child = Command::new("cat")
.stdinpiped()
.stdoutpiped()
.spawn()
.expect("Failed to spawn cat process");
let mut stdin = child.stdin.take().unwrap();
stdin.write_all(input.as_bytes()).unwrap();
drop(stdin);
let mut stdout = child.stdout.take().unwrap();
let mut output = String::new();
stdout.read_to_string(&mut output).unwrap();
child.wait().unwrap();
output
}
3. get_exit_code
pub fn get_exit_code(command: &str) -> i32 {
let status = Command::new("sh")
.args(["-c", command])
.status()
.expect("Failed to execute shell command");
status.code().unwrap_or(-1)
}
4. run_command_with_result
pub fn run_command_with_result(program: &str, args: &[&str]) -> io::Result<String> {
let output = Command::new(program)
.args(args)
.stdoutpiped()
.output()?;
String::from_utf8(output.stdout).map_err(|e| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("stdout is not valid UTF-8: {}", e),
)
})
}
5. pipe_through_grep
pub fn pipe_through_grep(pattern: &str, input: &str) -> String {
let mut child = Command::new("grep")
.arg(pattern)
.stdinpiped()
.stdoutpiped()
.spawn()
.expect("Failed to spawn grep process");
let mut stdin = child.stdin.take().unwrap();
stdin.write_all(input.as_bytes()).unwrap();
drop(stdin);
let mut stdout = child.stdout.take().unwrap();
let mut output = String::new();
stdout.read_to_string(&mut output).unwrap();
child.wait().unwrap();
output
}
五、记忆口诀
.output() 拿结果,.spawn() 能交互,.status() 只要码。
- 双向管道六步走:
spawn → take → write → drop → read → wait。
- 返回
Result 才能用 ?,返回普通值只能用 unwrap。
unwrap_or 兜底不崩溃,unwrap 失败就 panic。
map_err 换错误类型,? 原样传错误。