Skip to content
Select theme

How to parse arguments with clap

Short answer: Add clap with the derive feature, describe the command line as a struct, and call Cli::parse(). The parser, the --help text, and the error messages all come from that struct.

The examples stay in the args1 project from the previous article. Make yours with cargo new args1 if you don’t have it; the usage lines below will then show your project’s name instead.

Terminal window
cargo add clap --features derive

That writes this into Cargo.toml:

Cargo.toml
[dependencies]
clap = { version = "4.6.7", features = ["derive"] }

The exact version depends on when you run it; the derive feature is the part that matters. Without it you only get the builder API, which spells the same command line out longhand.

Replace src/main.rs with the greeter from the previous article, this time with the parsing done for you:

use clap::Parser;
#[derive(Parser)]
#[command(about = "Greet someone")]
struct Cli {
/// Who to greet
name: String,
/// How many times to greet them
#[arg(short, long, default_value_t = 1)]
count: u8,
}
fn main() {
let cli = Cli::parse();
for _ in 0..cli.count {
println!("hello, {}", cli.name);
}
}

A field with no #[arg] is a required positional argument, so name is the first one. #[arg(short, long)] lets count be given as -c or --count. And the /// comments are not notes for you; clap prints them in --help.

$ cargo run -q -- Ada
hello, Ada
$ cargo run -q -- Ada --count 2
hello, Ada
hello, Ada

-c 3 does the same as --count 3.

Leave out the required argument:

$ cargo run -q --
error: the following required arguments were not provided:
<NAME>
Usage: args1 <NAME>
For more information, try '--help'.
$ echo $?
2

That is the hand-written usage branch from the previous article, generated, and it exits with code 2 rather than panicking, which is what a shell script or a CI job checks for. Cli::parse() never returns an error to your code; on a bad command line it prints the message and exits, which is why there is no Result to unwrap.

And the help text, which nobody writes by hand:

$ cargo run -q -- --help
Greet someone
Usage: args1 [OPTIONS] <NAME>
Arguments:
<NAME> Who to greet
Options:
-c, --count <COUNT> How many times to greet them [default: 1]
-h, --help Print help

The about attribute is the first line, the doc comments fill the columns, and [default: 1] comes from default_value_t. An unknown flag is caught the same way, also with exit code 2.

Shaping the help text further (longer descriptions, value names, hiding an option) is a page of its own. Subcommands, the git-style verbs that take their own arguments, are an enum with #[derive(Subcommand)], and they come next.