shell_words

Function split

source
pub fn split(s: &str) -> Result<Vec<String>, ParseError>
Expand description

Splits command line into separate arguments, in much the same way Unix shell would, but without many of expansion the shell would perform.

The split functionality is compatible with behaviour of Unix shell, but with word expansions limited to quote removal, and without special token recognition rules for operators.

The result is exactly the same as one obtained from Unix shell as long as those unsupported features are not present in input: no operators, no variable assignments, no tilde expansion, no parameter expansion, no command substitution, no arithmetic expansion, no pathname expansion.

In case those unsupported shell features are present, the syntax that introduce them is interpreted literally.

§Errors

When input contains unmatched quote, an error is returned.

§Compatibility with other implementations

It should be fully compatible with g_shell_parse_argv from GLib, except that in GLib it is an error not to have any words after tokenization.

It is also very close to shlex.split available in Python standard library, when used in POSIX mode with support for comments. Though, shlex implementation diverges from POSIX, and from implementation contained herein in three aspects. First, it doesn’t support line continuations. Second, inside double quotes, the backslash characters retains its special meaning as an escape character only when followed by \ or ", whereas POSIX specifies that it should retain its special meaning when followed by: $, `, ", \, or a newline. Third, it treats carriage return as one of delimiters.

§Examples

Building an executable using compiler obtained from CC environment variable and compiler flags from both CFLAGS and CPPFLAGS. Similar to default build rule for C used in GNU Make:

use std::env::var;
use std::process::Command;

let cc = var("CC").unwrap_or_else(|_| "cc".to_owned());

let cflags_str = var("CFLAGS").unwrap_or_else(|_| String::new());
let cflags = shell_words::split(&cflags_str).expect("failed to parse CFLAGS");

let cppflags_str = var("CPPFLAGS").unwrap_or_else(|_| String::new());
let cppflags = shell_words::split(&cppflags_str).expect("failed to parse CPPFLAGS");

Command::new(cc)
    .args(cflags)
    .args(cppflags)
    .args(&["-c", "a.c", "-o", "a.out"])
    .spawn()
    .expect("failed to start subprocess")
    .wait()
    .expect("failed to wait for subprocess");