如何将带有多个参数的单个字符串传递给 std::process::Command?

Pet*_*ron 6 string child-process command-line-arguments rust

Rust 的std::process::Command类型要求进程参数通过单独传入.arg("-arg1").arg("-arg2")或作为字符串向量通过.args(&["-arg1", "-arg2"])。如何将字符串拆分为可以作为参数传递的向量?

Jmb*_*Jmb 5

将命令行字符串拆分为参数时,shell 所做的事情绝非易事,尤其是当您想处理诸如引用之类的事情时。例如,您的代码应通过以下断言:

assert_eq!(split(r#""foo\"bar""#), vec!["foo\"bar"]);
assert_eq!(split(r#""foo"#), vec!["\"foo"]);          // Or error
Run Code Online (Sandbox Code Playgroud)

除非您认为简单地在空格上拆分就足以满足您的用例,否则您真的应该使用像shell-wordsor 之类的板条箱shlexshlex优点是它可以返回一个迭代器,从而避免不必要的分配,但另一方面,它很容易错过上面第二个测试中的错误:

extern crate shell_words;
extern crate shlex;

use shell_words::split;
use shlex::Shlex;

fn main() {
    assert_eq!(split(r#"a b"#).unwrap(), vec!["a", "b"]);
    let mut lex = Shlex::new(r#"a b"#);
    assert_eq!(lex.by_ref().collect::<Vec<_>>(), vec!["a", "b"]);
    assert!(!lex.had_error);    // ? Don't forget this check!

    assert_eq!(split(r#"a "b c""#).unwrap(), vec!["a", "b c"]);
    let mut lex = Shlex::new(r#"a "b c""#);
    assert_eq!(lex.by_ref().collect::<Vec<_>>(), vec!["a", "b c"]);
    assert!(!lex.had_error);    // ? Don't forget this check!

    assert_eq!(split(r#""foo\"bar""#).unwrap(), vec!["foo\"bar"]);
    let mut lex = Shlex::new(r#""foo\"bar""#);
    assert_eq!(lex.by_ref().collect::<Vec<_>>(), vec!["foo\"bar"]);
    assert!(!lex.had_error);    // ? Don't forget this check!

    assert!(split(r#""foo"#).is_err());
    // assert_eq!(Shlex::new(r#""foo"#).collect::<Vec<_>>(), vec!["\"foo"]);

    let mut lex = Shlex::new(r#""foo"#);
    lex.by_ref().for_each (drop);
    assert!(lex.had_error);     // ? Don't forget this check!
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*ron -5

不支持引用参数的实现(但易于添加):

fn sh(command: &str) -> std::io::Result<std::process::Output> {
    let mut the_args = command.split(' '); // todo: support quoted strings
    let first: &str = the_args.next().unwrap();
    let rest: Vec<&str> = the_args.collect::<Vec<&str>>();
    std::process::Command::new(first).args(rest).output()
}

fn main() {
    let output = sh("ls -la").unwrap(); 
    let s = String::from_utf8_lossy(&output.stdout).to_string();
    println!("{:?}", s);
}
Run Code Online (Sandbox Code Playgroud)

您必须使用迭代器和字符串转换进行大量的歌舞表演。这让我困惑了好几天。我希望有人可以用一个处理带引号的参数字符串的基本解析器插话:)。

  • 或者您可以使用 [shell-words](https://crates.io/crates/shell-words) 箱来为您执行此操作... (2认同)
  • 您至少可以[避免创建向量](https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2015&amp;gist=04c8c711f66770ce1735efb0d8dd6195)。 (2认同)