Loading page…
Rust walkthroughs
Loading page…
Clap (Command Line Argument Parser) is a popular Rust library for parsing command line arguments. It provides a derive macro for declarative argument definition and a builder API for more control. Clap automatically generates help messages, handles argument validation, and supports subcommands.
Key concepts:
#[derive(Parser)] for declarative definition#[arg]-- prefixWhen to use Clap:
git)When NOT to use Clap:
std::env::args)use clap::Parser;
#[derive(Parser, Debug)]
#[command(name = "myapp")]\n#[command(about = "A simple CLI application", long_about = None)]
struct Args {
/// Name of the person to greet
#[arg(short, long)]
name: String,
/// Number of times to greet
#[arg(short, long, default_value_t = 1)]
count: u8,
}
fn main() {
let args = Args::parse();
for _ in 0..args.count {
println!("Hello, {}!", args.name);
}
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Input file path
input: String,
/// Output file path
output: String,
}
fn main() {
let args = Args::parse();
println!("Input: {}, Output: {}", args.input, args.output);
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Input file
input: String,
/// Output file (optional)
#[arg(short, long)]
output: Option<String>,
}
fn main() {
let args = Args::parse();
match args.output {
Some(path) => println!("Output to: {}", path),
None => println!("Output to stdout"),
}
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Enable verbose output
#[arg(short, long)]
verbose: bool,
/// Force overwrite
#[arg(short, long)]
force: bool,
}
fn main() {
let args = Args::parse();
if args.verbose {
println!("Verbose mode enabled");
}
if args.force {
println!("Force mode enabled");
}
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Port to listen on
#[arg(short, long, default_value = "8080")]
port: u16,
/// Host address
#[arg(long, default_value = "localhost")]
host: String,
}
fn main() {
let args = Args::parse();
println!("Listening on {}: {}", args.host, args.port);
}use clap::{Parser, Subcommand};
#[derive(Parser, Debug)]
#[command(name = "git")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Add files to staging
Add {
/// Files to add
#[arg(required = true)]
files: Vec<String>,
/// Add all files
#[arg(short, long)]
all: bool,
},
/// Commit changes
Commit {
/// Commit message
#[arg(short, long)]
message: String,
},
/// Push to remote
Push {
/// Remote name
#[arg(default_value = "origin")]
remote: String,
/// Branch name
#[arg(default_value = "main")]
branch: String,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Add { files, all } => {
if all {
println!("Adding all files");
} else {
println!("Adding files: {:?}", files);
}
}
Commands::Commit { message } => {
println!("Committing: {}", message);
}
Commands::Push { remote, branch } => {
println!("Pushing to {}/{}", remote, branch);
}
}
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Files to process
#[arg(short, long)]
files: Vec<String>,
}
fn main() {
let args = Args::parse();
println!("Processing {} files:", args.files.len());
for file in &args.files {
println!(" - {}", file);
}
}use clap::Parser;
use std::path::PathBuf;
#[derive(Parser, Debug)]
struct Args {
/// Input file (must exist)
#[arg(short, long, value_parser = clap::value_parser!(PathBuf))]
input: PathBuf,
/// Port number (1-65535)
#[arg(long, value_parser = validate_port)]
port: u16,
}
fn validate_port(s: &str) -> Result<u16, String> {
let port: u16 = s.parse().map_err(|_| "Invalid port number".to_string())?;
if port == 0 {
Err("Port cannot be zero".to_string())
} else {
Ok(port)
}
}
fn main() {
let args = Args::parse();
println!("Input: {:?}, Port: {}", args.input, args.port);
}use clap::Parser;
use std::net::SocketAddr;
#[derive(Parser, Debug)]
struct Args {
/// Server address (e.g., 127.0.0.1:8080)
#[arg(short, long, value_parser = parse_addr)]
addr: SocketAddr,
}
fn parse_addr(s: &str) -> Result<SocketAddr, String> {
s.parse().map_err(|_| format!("Invalid address: {}", s))
}
fn main() {
let args = Args::parse();
println!("Listening on {}", args.addr);
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// API key (from --api-key or API_KEY env var)
#[arg(long, env = "API_KEY")]
api_key: String,
/// Database URL
#[arg(long, env = "DATABASE_URL")]
database_url: Option<String>,
}
fn main() {
let args = Args::parse();
println!("API Key: {}", args.api_key);
if let Some(url) = args.database_url {
println!("Database: {}", url);
}
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Use HTTP
#[arg(long)]
http: bool,
/// Use HTTPS
#[arg(long, conflicts_with = "http")]
https: bool,
/// Verbose output
#[arg(short, long)]
verbose: bool,
}
fn main() {
let args = Args::parse();
if args.http {
println!("Using HTTP");
}
if args.https {
println!("Using HTTPS");
}
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Enable SSL
#[arg(long)]
ssl: bool,
/// SSL certificate path (required if --ssl)
#[arg(long, required_if_eq("ssl", "true"))]
ssl_cert: Option<String>,
}
fn main() {
let args = Args::parse();
println!("SSL: {:?}, Cert: {:?}", args.ssl, args.ssl_cert);
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Input file
#[arg(short, long, group = "input")]
file: Option<String>,
/// Input from stdin
#[arg(long, group = "input")]
stdin: bool,
}
fn main() {
let args = Args::parse();
if args.stdin {
println!("Reading from stdin");
} else if let Some(file) = args.file {
println!("Reading from file: {}", file);
}
}use clap::Parser;
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
/// Input file
input: String,
}
fn main() {
let args = Args::parse();
println!("Input: {}", args.input);
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Public argument
#[arg(long)]
public: String,
/// Hidden argument (not shown in help)
#[arg(long, hide = true)]
secret: Option<String>,
}
fn main() {
let args = Args::parse();
if let Some(secret) = args.secret {
println!("Secret provided");
}
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
/// Output file
#[arg(short = 'o', long = "output")]
output: String,
/// Verbose (can use -v or --verbose)
#[arg(short, long)]
verbose: bool,
}
fn main() {
let args = Args::parse();
println!("Output: {}, Verbose: {}", args.output, args.verbose);
}use clap::{Arg, Command};
fn main() {
let matches = Command::new("myapp")
.about("A CLI application")
.arg(
Arg::new("name")
.short('n')
.long("name")
.value_name("NAME")
.help("Name to greet")
.required(true),
)
.arg(
Arg::new("count")
.short('c')
.long("count")
.value_name("N")
.help("Number of greetings")
.default_value("1"),
)
.get_matches();
let name = matches.get_one::<String>("name").unwrap();
let count: u32 = matches.get_one::<String>("count").unwrap().parse().unwrap();
for _ in 0..count {
println!("Hello, {}!", name);
}
}use clap::{Parser, Subcommand};
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Database operations
Db {
#[command(subcommand)]
command: DbCommands,
},
}
#[derive(Subcommand)]
enum DbCommands {
/// Run migrations
Migrate {
/// Migration name
name: String,
},
/// Reset database
Reset,
/// Seed database
Seed {
/// Seed file
#[arg(short, long)]
file: String,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Db { command } => match command {
DbCommands::Migrate { name } => println!("Migrating: {}", name),
DbCommands::Reset => println!("Resetting database"),
DbCommands::Seed { file } => println!("Seeding from: {}", file),
},
}
}use clap::Parser;
#[derive(Parser, Debug)]
#[command(help_template = "{name} {version}\n{usage}\n\n{all-args}")]
struct Args {
/// Input file
input: String,
/// Output file
#[arg(short, long)]
output: Option<String>,
}
fn main() {
let args = Args::parse();
println!("Input: {:?}", args.input);
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
#[arg(short, long)]
name: String,
#[arg(short, long, default_value_t = 1)]
count: u8,
}
fn run(args: Args) {
for _ in 0..args.count {
println!("Hello, {}!", args.name);
}
}
fn main() {
let args = Args::parse();
run(args);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_greeting() {
let args = Args::try_parse_from(["test", "--name", "World", "--count", "2"]);
assert!(args.is_ok());
let args = args.unwrap();
assert_eq!(args.name, "World");
assert_eq!(args.count, 2);
}
#[test]
fn test_missing_required() {
let result = Args::try_parse_from(["test"]);
assert!(result.is_err());
}
}use clap::Parser;
#[derive(Parser, Debug)]
#[command(color = clap::ColorChoice::Always)]
struct Args {
/// Input file
input: String,
}
fn main() {
let args = Args::parse();
println!("Input: {}", args.input);
}use clap::Parser;
#[derive(Parser, Debug)]
struct Args {
#[arg(short, long)]
name: String,
}
fn main() {
// Parse from custom iterator
let args = Args::parse_from(["myapp", "--name", "Alice"]);
println!("Name: {}", args.name);
// Or try_parse_from for error handling
match Args::try_parse_from(["myapp", "--name", "Bob"]) {
Ok(args) => println!("Parsed: {}", args.name),
Err(e) => println!("Error: {}", e),
}
}Clap Key Imports:
use clap::{Parser, Subcommand};Derive Macros:
| Macro | Description |
|-------|-------------|
| #[derive(Parser)] | Main argument struct |
| #[derive(Subcommand)] | Subcommand enum |
| #[derive(Args)] | Nested argument groups |
Common Attributes:
| Attribute | Description |
|-----------|-------------|
| short | Short flag (-x) |
| long | Long flag (--name) |
| default_value | Default if not provided |
| required | Must be provided |
| help | Help text |
| env | Environment variable |
| conflicts_with | Mutually exclusive |
Argument Types:
| Type | Example |
|------|---------|
| Positional | input: String |
| Option | #[arg(short, long)] output: Option<String> |
| Flag | #[arg(short, long)] verbose: bool |
| Multiple | #[arg(short, long)] files: Vec<String> |
Subcommand Structure:
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Add { /* ... */ },
Remove { /* ... */ },
}Key Points:
try_parse_from