lazycmd/
cmd.rs

1use std::{ffi::OsStr, io::{self, BufRead}, process::{Child, Command, Stdio}};
2
3use anyhow::{anyhow, Result};
4
5/// 执行命令
6///
7/// Examples
8///
9/// ```
10/// use lazycmd::output;
11///
12/// let out = output(["which", "curl"]).unwrap();
13///
14/// assert_eq!(out, "/usr/bin/curl");
15/// ```
16pub fn output<I, S>(args: I) -> Result<String>
17where
18    I: IntoIterator<Item = S>,
19    S: AsRef<OsStr>,
20{
21    let args: Vec<S> = args.into_iter().collect();
22    let output = Command::new(&args[0])
23        .args(&args[1..])
24        .output()?;
25
26    let outerr = String::from_utf8_lossy(&output.stderr);
27    if !outerr.is_empty() {
28        if let Some(e) = outerr.strip_suffix("\n") {
29            return Err(anyhow!("{e}"));
30        } else {
31            return Err(anyhow!("{outerr}"));
32        }
33    }
34    let out = String::from_utf8_lossy(&output.stdout);
35    if let Some(o) = out.strip_suffix("\n") {
36        return Ok(o.to_string());
37    }
38    Ok(out.to_string())
39}
40
41
42/// 运行命令并实时输出
43///
44/// Examples
45///
46/// ```
47/// use lazycmd::spawn;
48///
49/// spawn(["ls", "-l"]).unwrap();
50/// ```
51pub fn spawn<I, S>(args: I) -> Result<Vec<String>>
52where
53    I: IntoIterator<Item = S>,
54    S: AsRef<OsStr>,
55{
56    let args: Vec<S> = args.into_iter().collect();
57    let mut child: Child = Command::new(&args[0])
58        .args(&args[1..])
59        .stdout(Stdio::piped()) // 将标准输出设置为管道
60        .spawn()?; // 启动命令
61
62    // 获取标准输出的句柄
63    let stdout = child.stdout.take().ok_or_else(|| anyhow!("Could not capture standard output"))?;
64
65    // 创建一个 BufReader 来逐行读取输出
66    let reader = io::BufReader::new(stdout);
67
68    // 逐行读取输出并打印
69    let mut result = Vec::new();
70    for line in reader.lines() {
71        let line = line?;
72        println!("{}", line);
73        result.push(line);
74    }
75
76    // 等待命令完成
77    let _ = child.wait()?;
78    Ok(result)
79}
80