Splitting the command line
Before we can run ls -la, we need to see it as a command and its arguments.
The obvious tokenizer is split_whitespace, and for milestone two the obvious
tokenizer is the right one:
fn tokenize(line: &str) -> Vec<String> {
line.split_whitespace().map(str::to_string).collect()
}
Wire it into the loop from milestone one and print the pieces. The first word is the program; the rest are its arguments.
challenge: handle quoted arguments
split_whitespace breaks echo "hello world" into three tokens, but a real
shell yields two. Extend tokenize so double-quoted spans keep their spaces.
Keep the signature; you will want to walk the characters yourself.
solution
Walk the characters with a flag for whether you are inside quotes:
fn tokenize(line: &str) -> Vec<String> {
let mut tokens = Vec::new();
let mut current = String::new();
let mut in_quotes = false;
for c in line.chars() {
match c {
'"' => in_quotes = !in_quotes,
c if c.is_whitespace() && !in_quotes => {
if !current.is_empty() {
tokens.push(std::mem::take(&mut current));
}
}
c => current.push(c),
}
}
if !current.is_empty() {
tokens.push(current);
}
tokens
}
Unterminated quotes silently close at end of line — a real shell would keep reading. That wart becomes a milestone of its own later.