Crate for splitting a string like bash?

Let's say I have some some string like this:

my-command --arg1 "this is some text" --arg2 text

If I were to execute that in bash, my-command would be invoked with the following array of arguments:

[src/main.rs:2] std::env::args().collect::<Vec<_>>() = [
    "my-command",
    "--arg1",
    "this is some text",
    "--arg2",
    "text",
]

My question is: Is there a crate that will split up a string the same way bash does?

https://lib.rs/search?q=shell+words first results:

2 Likes

I got this far by the time I saw your comment - FWIW, it works well enough, but I'm guessing these solutions are better tested. :slight_smile: I think I'll go with shell-words since it has the most downloads.

struct CommandSplitter<'a> {
    chars: Chars<'a>,
}

impl<'a> CommandSplitter<'a> {
    fn new(command: &'a str) -> Self {
        Self {
            chars: command.chars(),
        }
    }
}

impl<'a> Iterator for CommandSplitter<'a> {
    type Item = String;
    fn next(&mut self) -> Option<Self::Item> {
        let mut out = String::new();
        let mut escaped = false;
        let mut quote_char = None;
        while let Some(c) = self.chars.next() {
            if escaped {
                out.push(c);
                escaped = false;
            } else if c == '\\' {
                escaped = true;
            } else if let Some(qc) = quote_char {
                if c == qc {
                    quote_char = None;
                } else {
                    out.push(c);
                }
            } else if c == '\'' || c == '"' {
                quote_char = Some(c);
            } else if c.is_whitespace() {
                if !out.is_empty() {
                    return Some(out);
                } else {
                    continue;
                }
            } else {
                out.push(c);
            }
        }

        if !out.is_empty() {
            Some(out)
        } else {
            None
        }
    }
}

I believe you are looking for arguments parsing not string manipulation.

https://github.com/clap-rs/clap is popular for argument parsing.

Bash style string manipulation is very powerful. It would be nice to see a similar rust library for it.
https://www.tldp.org/LDP/abs/html/string-manipulation.html

I wasn't looking for argument parsing. In fact, what I wanted to do was take a flat string and feed it in to clap. @Yandros' answer allows me to do that.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.