Как передать одну строку с несколькими аргументами в std :: process :: Command? - PullRequest
0 голосов
/ 27 ноября 2018

Тип Rust std::process::Command требует, чтобы аргументы процесса передавались индивидуально через .arg("-arg1").arg("-arg2") или как вектор строк через .args(&["-arg1", "-arg2"]).Как разделить строку на вектор, который может быть передан в качестве аргумента?

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

То, что делают оболочки при разбиении строки командной строки на аргументы, далеко не тривиально, особенно когда вы хотите обрабатывать такие вещи, как цитирование.Например, ваш код должен передавать следующие утверждения:

assert_eq!(split(r#""foo\"bar""#), vec!["foo\"bar"]);
assert_eq!(split(r#""foo"#), vec!["\"foo"]);          // Or error

Если вы не считаете, что простого разбиения на пробел достаточно для вашего варианта использования, вам действительно следует использовать ящик типа shell-words или shlex.shlex предоставляет преимущество в том, что он может возвращать итератор, что позволяет избежать ненужных распределений, но, с другой стороны, позволяет легко пропустить ошибку во втором тесте, приведенном выше:

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!
}
0 голосов
/ 27 ноября 2018

Реализация, которая не поддерживает аргументы в кавычках (но их легко добавить):

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);
}

Вы должны сделать немало песен и танцев с итераторами и преобразованиями строк.Это сбило меня с толку на несколько дней.Я надеюсь, что кто-то может подключиться к базовому парсеру, который обрабатывает строки аргументов в кавычках:).

...