RustCommand Line Arguments

Introduction

Rust's standard library does not contain a proper argument parser (unlike argparse in Python), instead preferring to leave this to third-party crates. These examples will show the usage of both the standard library (to form a crude argument handler) and the clap library which can parse command-line arguments more effectively.

Syntax

  • use std::env; // Import the env module
  • let args = env::args(); // Store an Args iterator in the args variable.

Using std::env::args()

You can access the command line arguments passed to your program using the std::env::args() function. This returns an Args iterator which you can loop over or collect into a Vec.

Iterating Through Arguments

use std::env;

fn main() {
    for argument in env::args() {
        if argument == "--help" {
            println!("You passed --help as one of the arguments!");
        }
    }
}

Collecting into a Vec

use std::env;

fn main() {
    let arguments: Vec<String> = env::args().collect();
    println!("{} arguments passed", arguments.len());
}

You might get more arguments than you expect if you call your program like this:

./example

Although it looks like no arguments were passed, the first argument is (usually) the name of the executable. This isn't a guarantee though, so you should always validate and filter the arguments you get.

Using clap

For larger command line programs, using std::env::args() is quite tedious and difficult to manage. You can use clap to handle your command line interface, which will parse arguments, generate help displays and avoid bugs.

There are several patterns that you can use with clap, and each one provides a different amount of flexibility.

Builder Pattern

This is the most verbose (and flexible) method, so it is useful when you need fine-grained control of your CLI.

clap distinguishes between subcommands and arguments. Subcommands act like independent subprograms in your main program, just like cargo run and git push. They can have their own command-line options and inputs. Arguments are simple flags such as --verbose, and they can take inputs (e.g. --message "Hello, world")

extern crate clap;
use clap::{Arg, App, SubCommand};

fn main() {
    let app = App::new("Foo Server")
        .about("Serves foos to the world!")
        .version("v0.1.0")
        .author("Foo (@Example on GitHub)")
        .subcommand(SubCommand::with_name("run")
            .about("Runs the Foo Server")
            .arg(Arg::with_name("debug")
                .short("D")
                .about("Sends debug foos instead of normal foos.")))

    // This parses the command-line arguments for use.
    let matches = app.get_matches();

    // We can get the subcommand used with matches.subcommand(), which
    // returns a tuple of (&str, Option<ArgMatches>) where the &str
    // is the name of the subcommand, and the ArgMatches is an 
    // ArgMatches struct: 
    // https://docs.rs/clap/2.13.0/clap/struct.ArgMatches.html

    if let ("run", Some(run_matches)) = app.subcommand() {
        println!("Run was used!");
    }
}