Struct clap::ArgMatches
source · [−]pub struct ArgMatches { /* private fields */ }
Expand description
Container for parse results.
Used to get information about the arguments that were supplied to the program at runtime by
the user. New instances of this struct are obtained by using the Command::get_matches
family of
methods.
Examples
let matches = Command::new("MyApp")
.arg(Arg::new("out")
.long("output")
.required(true)
.action(ArgAction::Set)
.default_value("-"))
.arg(Arg::new("cfg")
.short('c')
.action(ArgAction::Set))
.get_matches(); // builds the instance of ArgMatches
// to get information about the "cfg" argument we created, such as the value supplied we use
// various ArgMatches methods, such as [ArgMatches::get_one]
if let Some(c) = matches.get_one::<String>("cfg") {
println!("Value for -c: {}", c);
}
// The ArgMatches::get_one method returns an Option because the user may not have supplied
// that argument at runtime. But if we specified that the argument was "required" as we did
// with the "out" argument, we can safely unwrap because `clap` verifies that was actually
// used at runtime.
println!("Value for --output: {}", matches.get_one::<String>("out").unwrap());
// You can check the presence of an argument's values
if matches.contains_id("out") {
// However, if you want to know where the value came from
if matches.value_source("out").expect("checked contains_id") == ValueSource::CommandLine {
println!("`out` set by user");
} else {
println!("`out` is defaulted");
}
}
Implementations
sourceimpl ArgMatches
impl ArgMatches
sourcepub fn get_one<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Option<&T>
pub fn get_one<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Option<&T>
Gets the value of a specific option or positional argument.
i.e. an argument that takes an additional value at runtime.
Returns an error if the wrong type was used.
Returns None
if the option wasn’t present.
NOTE: This will always return Some(value)
if default_value
has been set.
ArgMatches::value_source
can be used to check if a value is present at runtime.
Panic
If the argument definition and access mismatch. To handle this case programmatically, see
ArgMatches::try_get_one
.
Examples
let m = Command::new("myapp")
.arg(Arg::new("port")
.value_parser(value_parser!(usize))
.action(ArgAction::Set)
.required(true))
.get_matches_from(vec!["myapp", "2020"]);
let port: usize = *m
.get_one("port")
.expect("`port`is required");
assert_eq!(port, 2020);
Examples found in repository?
More examples
3 4 5 6 7 8 9 10 11 12 13 14
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
Arg::new("name")
.short('n')
.long("name")
.action(ArgAction::Append),
)
.get_matches();
println!("name: {:?}", matches.get_one::<String>("name"));
}
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
arg!([PORT])
.value_parser(value_parser!(u16))
.default_value("2020"),
)
.get_matches();
println!(
"port: {:?}",
matches
.get_one::<u16>("PORT")
.expect("default ensures there is always a value")
);
}
- examples/tutorial_builder/02_crate.rs
- examples/tutorial_builder/02_app_settings.rs
- examples/tutorial_builder/04_02_validate.rs
- examples/tutorial_builder/04_02_parse.rs
- examples/tutorial_builder/02_apps.rs
- examples/tutorial_builder/04_01_enum.rs
- examples/tutorial_builder/04_01_possible.rs
- examples/tutorial_builder/03_04_subcommands.rs
- examples/cargo-example.rs
- examples/escaped-positional.rs
- examples/tutorial_builder/01_quick.rs
- examples/tutorial_builder/04_03_relations.rs
- examples/git.rs
- examples/tutorial_builder/04_04_custom.rs
sourcepub fn get_count(&self, id: &str) -> u8
pub fn get_count(&self, id: &str) -> u8
Gets the value of a specific ArgAction::Count
flag
Panic
If the argument’s action is not ArgAction::Count
Examples
let cmd = Command::new("mycmd")
.arg(
Arg::new("flag")
.long("flag")
.action(clap::ArgAction::Count)
);
let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
assert_eq!(
matches.get_count("flag"),
2
);
Examples found in repository?
3 4 5 6 7 8 9 10 11 12 13 14
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.action(ArgAction::Count),
)
.get_matches();
println!("verbose: {:?}", matches.get_count("verbose"));
}
sourcepub fn get_flag(&self, id: &str) -> bool
pub fn get_flag(&self, id: &str) -> bool
Gets the value of a specific ArgAction::SetTrue
or ArgAction::SetFalse
flag
Panic
If the argument’s action is not ArgAction::SetTrue
or ArgAction::SetFalse
Examples
let cmd = Command::new("mycmd")
.arg(
Arg::new("flag")
.long("flag")
.action(clap::ArgAction::SetTrue)
);
let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
assert!(matches.contains_id("flag"));
assert_eq!(
matches.get_flag("flag"),
true
);
Examples found in repository?
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
Ok(Self {
foo: matches.get_flag("foo"),
bar: matches.get_flag("bar"),
quuz: matches.remove_one::<String>("quuz"),
})
}
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
let mut matches = matches.clone();
self.update_from_arg_matches_mut(&mut matches)
}
fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
self.foo |= matches.get_flag("foo");
self.bar |= matches.get_flag("bar");
if let Some(quuz) = matches.remove_one::<String>("quuz") {
self.quuz = Some(quuz);
}
Ok(())
}
More examples
3 4 5 6 7 8 9 10 11 12 13 14
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.action(ArgAction::SetTrue),
)
.get_matches();
println!("verbose: {:?}", matches.get_flag("verbose"));
}
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
fn main() {
let cli = Command::new("CLI").arg(arg!(-b - -built).action(clap::ArgAction::SetTrue));
// Augment built args with derived args
let cli = DerivedArgs::augment_args(cli);
let matches = cli.get_matches();
println!("Value of built: {:?}", matches.get_flag("built"));
println!(
"Value of derived via ArgMatches: {:?}",
matches.get_flag("derived")
);
// Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
// This is the main benefit of using derived arguments.
let derived_matches = DerivedArgs::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();
println!("Value of derived: {:#?}", derived_matches);
}
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
fn main() {
let matches = command!() // requires `cargo` feature
.arg(arg!(eff: -f).action(ArgAction::SetTrue))
.arg(arg!(pea: -p <PEAR>).value_parser(value_parser!(String)))
.arg(
// Indicates that `slop` is only accessible after `--`.
arg!(slop: [SLOP])
.num_args(1..)
.last(true)
.value_parser(value_parser!(String)),
)
.get_matches();
// This is what will happen with `myprog -f -p=bob -- sloppy slop slop`...
// -f used: true
println!("-f used: {:?}", matches.get_flag("eff"));
// -p's value: Some("bob")
println!("-p's value: {:?}", matches.get_one::<String>("pea"));
// 'slops' values: Some(["sloppy", "slop", "slop"])
println!(
"'slops' values: {:?}",
matches
.get_many::<String>("slop")
.map(|vals| vals.collect::<Vec<_>>())
.unwrap_or_default()
);
// Continued program logic goes here...
}
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
fn main() {
// Create application like normal
let matches = command!() // requires `cargo` feature
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually"))
.arg(arg!(--major "auto inc major").action(ArgAction::SetTrue))
.arg(arg!(--minor "auto inc minor").action(ArgAction::SetTrue))
.arg(arg!(--patch "auto inc patch").action(ArgAction::SetTrue))
// Create a group, make it required, and add the above arguments
.group(
ArgGroup::new("vers")
.required(true)
.args(["set-ver", "major", "minor", "patch"]),
)
// Arguments can also be added to a group individually, these two arguments
// are part of the "input" group which is not required
.arg(
arg!([INPUT_FILE] "some regular input")
.value_parser(value_parser!(PathBuf))
.group("input"),
)
.arg(
arg!(--"spec-in" <SPEC_IN> "some special input argument")
.value_parser(value_parser!(PathBuf))
.group("input"),
)
// Now let's assume we have a -c [config] argument which requires one of
// (but **not** both) the "input" arguments
.arg(
arg!(config: -c <CONFIG>)
.value_parser(value_parser!(PathBuf))
.requires("input"),
)
.get_matches();
// Let's assume the old version 1.2.3
let mut major = 1;
let mut minor = 2;
let mut patch = 3;
// See if --set-ver was used to set the version manually
let version = if let Some(ver) = matches.get_one::<String>("set-ver") {
ver.to_owned()
} else {
// Increment the one requested (in a real program, we'd reset the lower numbers)
let (maj, min, pat) = (
matches.get_flag("major"),
matches.get_flag("minor"),
matches.get_flag("patch"),
);
match (maj, min, pat) {
(true, _, _) => major += 1,
(_, true, _) => minor += 1,
(_, _, true) => patch += 1,
_ => unreachable!(),
};
format!("{}.{}.{}", major, minor, patch)
};
println!("Version: {}", version);
// Check for usage of -c
if matches.contains_id("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.unwrap_or_else(|| matches.get_one::<PathBuf>("spec-in").unwrap())
.display();
println!(
"Doing work using input {} and config {}",
input,
matches.get_one::<PathBuf>("config").unwrap().display()
);
}
}
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
fn main() {
// Create application like normal
let mut cmd = command!() // requires `cargo` feature
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually"))
.arg(arg!(--major "auto inc major").action(ArgAction::SetTrue))
.arg(arg!(--minor "auto inc minor").action(ArgAction::SetTrue))
.arg(arg!(--patch "auto inc patch").action(ArgAction::SetTrue))
// Arguments can also be added to a group individually, these two arguments
// are part of the "input" group which is not required
.arg(arg!([INPUT_FILE] "some regular input").value_parser(value_parser!(PathBuf)))
.arg(
arg!(--"spec-in" <SPEC_IN> "some special input argument")
.value_parser(value_parser!(PathBuf)),
)
// Now let's assume we have a -c [config] argument which requires one of
// (but **not** both) the "input" arguments
.arg(arg!(config: -c <CONFIG>).value_parser(value_parser!(PathBuf)));
let matches = cmd.get_matches_mut();
// Let's assume the old version 1.2.3
let mut major = 1;
let mut minor = 2;
let mut patch = 3;
// See if --set-ver was used to set the version manually
let version = if let Some(ver) = matches.get_one::<String>("set-ver") {
if matches.get_flag("major") || matches.get_flag("minor") || matches.get_flag("patch") {
cmd.error(
ErrorKind::ArgumentConflict,
"Can't do relative and absolute version change",
)
.exit();
}
ver.to_string()
} else {
// Increment the one requested (in a real program, we'd reset the lower numbers)
let (maj, min, pat) = (
matches.get_flag("major"),
matches.get_flag("minor"),
matches.get_flag("patch"),
);
match (maj, min, pat) {
(true, false, false) => major += 1,
(false, true, false) => minor += 1,
(false, false, true) => patch += 1,
_ => {
cmd.error(
ErrorKind::ArgumentConflict,
"Can only modify one version field",
)
.exit();
}
};
format!("{}.{}.{}", major, minor, patch)
};
println!("Version: {}", version);
// Check for usage of -c
if matches.contains_id("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.or_else(|| matches.get_one::<PathBuf>("spec-in"))
.unwrap_or_else(|| {
cmd.error(
ErrorKind::MissingRequiredArgument,
"INPUT_FILE or --spec-in is required when using --config",
)
.exit()
})
.display();
println!(
"Doing work using input {} and config {}",
input,
matches.get_one::<PathBuf>("config").unwrap().display()
);
}
}
sourcepub fn get_many<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Option<ValuesRef<'_, T>>
pub fn get_many<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Option<ValuesRef<'_, T>>
Iterate over values of a specific option or positional argument.
i.e. an argument that takes multiple values at runtime.
Returns an error if the wrong type was used.
Returns None
if the option wasn’t present.
Panic
If the argument definition and access mismatch. To handle this case programmatically, see
ArgMatches::try_get_many
.
Examples
let m = Command::new("myprog")
.arg(Arg::new("ports")
.action(ArgAction::Append)
.value_parser(value_parser!(usize))
.short('p')
.required(true))
.get_matches_from(vec![
"myprog", "-p", "22", "-p", "80", "-p", "2020"
]);
let vals: Vec<usize> = m.get_many("ports")
.expect("`port`is required")
.copied()
.collect();
assert_eq!(vals, [22, 80, 2020]);
Examples found in repository?
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
fn main() {
let matches = command!() // requires `cargo` feature
.arg(arg!(eff: -f).action(ArgAction::SetTrue))
.arg(arg!(pea: -p <PEAR>).value_parser(value_parser!(String)))
.arg(
// Indicates that `slop` is only accessible after `--`.
arg!(slop: [SLOP])
.num_args(1..)
.last(true)
.value_parser(value_parser!(String)),
)
.get_matches();
// This is what will happen with `myprog -f -p=bob -- sloppy slop slop`...
// -f used: true
println!("-f used: {:?}", matches.get_flag("eff"));
// -p's value: Some("bob")
println!("-p's value: {:?}", matches.get_one::<String>("pea"));
// 'slops' values: Some(["sloppy", "slop", "slop"])
println!(
"'slops' values: {:?}",
matches
.get_many::<String>("slop")
.map(|vals| vals.collect::<Vec<_>>())
.unwrap_or_default()
);
// Continued program logic goes here...
}
More examples
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
fn main() {
let matches = cli().get_matches();
match matches.subcommand() {
Some(("clone", sub_matches)) => {
println!(
"Cloning {}",
sub_matches.get_one::<String>("REMOTE").expect("required")
);
}
Some(("diff", sub_matches)) => {
let color = sub_matches
.get_one::<String>("color")
.map(|s| s.as_str())
.expect("defaulted in clap");
let mut base = sub_matches.get_one::<String>("base").map(|s| s.as_str());
let mut head = sub_matches.get_one::<String>("head").map(|s| s.as_str());
let mut path = sub_matches.get_one::<String>("path").map(|s| s.as_str());
if path.is_none() {
path = head;
head = None;
if path.is_none() {
path = base;
base = None;
}
}
let base = base.unwrap_or("stage");
let head = head.unwrap_or("worktree");
let path = path.unwrap_or("");
println!("Diffing {}..{} {} (color={})", base, head, path, color);
}
Some(("push", sub_matches)) => {
println!(
"Pushing to {}",
sub_matches.get_one::<String>("REMOTE").expect("required")
);
}
Some(("add", sub_matches)) => {
let paths = sub_matches
.get_many::<PathBuf>("PATH")
.into_iter()
.flatten()
.collect::<Vec<_>>();
println!("Adding {:?}", paths);
}
Some(("stash", sub_matches)) => {
let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches));
match stash_command {
("apply", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Applying {:?}", stash);
}
("pop", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Popping {:?}", stash);
}
("push", sub_matches) => {
let message = sub_matches.get_one::<String>("message");
println!("Pushing {:?}", message);
}
(name, _) => {
unreachable!("Unsupported subcommand `{}`", name)
}
}
}
Some((ext, sub_matches)) => {
let args = sub_matches
.get_many::<OsString>("")
.into_iter()
.flatten()
.collect::<Vec<_>>();
println!("Calling out to {:?} with {:?}", ext, args);
}
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!()
}
// Continued program logic goes here...
}
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
fn main() {
let matches = Command::new("pacman")
.about("package manager utility")
.version("5.2.1")
.subcommand_required(true)
.arg_required_else_help(true)
.author("Pacman Development Team")
// Query subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
Command::new("query")
.short_flag('Q')
.long_flag("query")
.about("Query the package database.")
.arg(
Arg::new("search")
.short('s')
.long("search")
.help("search locally installed packages for matching strings")
.conflicts_with("info")
.action(ArgAction::Set)
.num_args(1..),
)
.arg(
Arg::new("info")
.long("info")
.short('i')
.conflicts_with("search")
.help("view package information")
.action(ArgAction::Set)
.num_args(1..),
),
)
// Sync subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
Command::new("sync")
.short_flag('S')
.long_flag("sync")
.about("Synchronize packages.")
.arg(
Arg::new("search")
.short('s')
.long("search")
.conflicts_with("info")
.action(ArgAction::Set)
.num_args(1..)
.help("search remote repositories for matching strings"),
)
.arg(
Arg::new("info")
.long("info")
.conflicts_with("search")
.short('i')
.action(ArgAction::SetTrue)
.help("view package information"),
)
.arg(
Arg::new("package")
.help("packages")
.required_unless_present("search")
.action(ArgAction::Set)
.num_args(1..),
),
)
.get_matches();
match matches.subcommand() {
Some(("sync", sync_matches)) => {
if sync_matches.contains_id("search") {
let packages: Vec<_> = sync_matches
.get_many::<String>("search")
.expect("contains_id")
.map(|s| s.as_str())
.collect();
let values = packages.join(", ");
println!("Searching for {}...", values);
return;
}
let packages: Vec<_> = sync_matches
.get_many::<String>("package")
.expect("is present")
.map(|s| s.as_str())
.collect();
let values = packages.join(", ");
if sync_matches.get_flag("info") {
println!("Retrieving info for {}...", values);
} else {
println!("Installing {}...", values);
}
}
Some(("query", query_matches)) => {
if let Some(packages) = query_matches.get_many::<String>("info") {
let comma_sep = packages.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Retrieving info for {}...", comma_sep);
} else if let Some(queries) = query_matches.get_many::<String>("search") {
let comma_sep = queries.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Searching Locally for {}...", comma_sep);
} else {
println!("Displaying all locally installed packages...");
}
}
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachable
}
}
sourcepub fn get_raw(&self, id: &str) -> Option<RawValues<'_>>
pub fn get_raw(&self, id: &str) -> Option<RawValues<'_>>
Iterate over the original argument values.
An OsStr
on Unix-like systems is any series of bytes, regardless of whether or not they
contain valid UTF-8. Since String
s in Rust are guaranteed to be valid UTF-8, a valid
filename on a Unix system as an argument value may contain invalid UTF-8.
Returns None
if the option wasn’t present.
Panic
If the argument definition and access mismatch. To handle this case programmatically, see
ArgMatches::try_get_raw
.
Examples
use std::path::PathBuf;
let m = Command::new("utf8")
.arg(arg!(<arg> ... "some arg").value_parser(value_parser!(PathBuf)))
.get_matches_from(vec![OsString::from("myprog"),
// "Hi"
OsString::from_vec(vec![b'H', b'i']),
// "{0xe9}!"
OsString::from_vec(vec![0xe9, b'!'])]);
let mut itr = m.get_raw("arg")
.expect("`port`is required")
.into_iter();
assert_eq!(itr.next(), Some(OsStr::new("Hi")));
assert_eq!(itr.next(), Some(OsStr::from_bytes(&[0xe9, b'!'])));
assert_eq!(itr.next(), None);
sourcepub fn remove_one<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Option<T>
pub fn remove_one<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Option<T>
Returns the value of a specific option or positional argument.
i.e. an argument that takes an additional value at runtime.
Returns an error if the wrong type was used. No item will have been removed.
Returns None
if the option wasn’t present.
NOTE: This will always return Some(value)
if default_value
has been set.
ArgMatches::value_source
can be used to check if a value is present at runtime.
Panic
If the argument definition and access mismatch. To handle this case programmatically, see
ArgMatches::try_remove_one
.
Examples
let mut m = Command::new("myprog")
.arg(Arg::new("file")
.required(true)
.action(ArgAction::Set))
.get_matches_from(vec![
"myprog", "file.txt",
]);
let vals: String = m.remove_one("file")
.expect("`file`is required");
assert_eq!(vals, "file.txt");
Examples found in repository?
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
Ok(Self {
foo: matches.get_flag("foo"),
bar: matches.get_flag("bar"),
quuz: matches.remove_one::<String>("quuz"),
})
}
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
let mut matches = matches.clone();
self.update_from_arg_matches_mut(&mut matches)
}
fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
self.foo |= matches.get_flag("foo");
self.bar |= matches.get_flag("bar");
if let Some(quuz) = matches.remove_one::<String>("quuz") {
self.quuz = Some(quuz);
}
Ok(())
}
sourcepub fn remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Option<Values<T>>
pub fn remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Option<Values<T>>
Return values of a specific option or positional argument.
i.e. an argument that takes multiple values at runtime.
Returns an error if the wrong type was used. No item will have been removed.
Returns None
if the option wasn’t present.
Panic
If the argument definition and access mismatch. To handle this case programmatically, see
ArgMatches::try_remove_many
.
Examples
let mut m = Command::new("myprog")
.arg(Arg::new("file")
.action(ArgAction::Append)
.num_args(1..)
.required(true))
.get_matches_from(vec![
"myprog", "file1.txt", "file2.txt", "file3.txt", "file4.txt",
]);
let vals: Vec<String> = m.remove_many("file")
.expect("`file`is required")
.collect();
assert_eq!(vals, ["file1.txt", "file2.txt", "file3.txt", "file4.txt"]);
sourcepub fn contains_id(&self, id: &str) -> bool
pub fn contains_id(&self, id: &str) -> bool
Check if values are present for the argument or group id
NOTE: This will always return true
if default_value
has been set.
ArgMatches::value_source
can be used to check if a value is present at runtime.
Panics
If id
is is not a valid argument or group name. To handle this case programmatically, see
ArgMatches::try_contains_id
.
Examples
let m = Command::new("myprog")
.arg(Arg::new("debug")
.short('d')
.action(ArgAction::SetTrue))
.get_matches_from(vec![
"myprog", "-d"
]);
assert!(m.contains_id("debug"));
Examples found in repository?
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
fn main() {
let cmd = Command::new(env!("CARGO_CRATE_NAME"))
.multicall(true)
.subcommand(
Command::new("busybox")
.arg_required_else_help(true)
.subcommand_value_name("APPLET")
.subcommand_help_heading("APPLETS")
.arg(
Arg::new("install")
.long("install")
.help("Install hardlinks for all subcommands in path")
.exclusive(true)
.action(ArgAction::Set)
.default_missing_value("/usr/local/bin")
.value_parser(value_parser!(PathBuf)),
)
.subcommands(applet_commands()),
)
.subcommands(applet_commands());
let matches = cmd.get_matches();
let mut subcommand = matches.subcommand();
if let Some(("busybox", cmd)) = subcommand {
if cmd.contains_id("install") {
unimplemented!("Make hardlinks to the executable here");
}
subcommand = cmd.subcommand();
}
match subcommand {
Some(("false", _)) => exit(1),
Some(("true", _)) => exit(0),
_ => unreachable!("parser should ensure only valid subcommand names are used"),
}
}
More examples
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
fn main() {
// Create application like normal
let matches = command!() // requires `cargo` feature
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually"))
.arg(arg!(--major "auto inc major").action(ArgAction::SetTrue))
.arg(arg!(--minor "auto inc minor").action(ArgAction::SetTrue))
.arg(arg!(--patch "auto inc patch").action(ArgAction::SetTrue))
// Create a group, make it required, and add the above arguments
.group(
ArgGroup::new("vers")
.required(true)
.args(["set-ver", "major", "minor", "patch"]),
)
// Arguments can also be added to a group individually, these two arguments
// are part of the "input" group which is not required
.arg(
arg!([INPUT_FILE] "some regular input")
.value_parser(value_parser!(PathBuf))
.group("input"),
)
.arg(
arg!(--"spec-in" <SPEC_IN> "some special input argument")
.value_parser(value_parser!(PathBuf))
.group("input"),
)
// Now let's assume we have a -c [config] argument which requires one of
// (but **not** both) the "input" arguments
.arg(
arg!(config: -c <CONFIG>)
.value_parser(value_parser!(PathBuf))
.requires("input"),
)
.get_matches();
// Let's assume the old version 1.2.3
let mut major = 1;
let mut minor = 2;
let mut patch = 3;
// See if --set-ver was used to set the version manually
let version = if let Some(ver) = matches.get_one::<String>("set-ver") {
ver.to_owned()
} else {
// Increment the one requested (in a real program, we'd reset the lower numbers)
let (maj, min, pat) = (
matches.get_flag("major"),
matches.get_flag("minor"),
matches.get_flag("patch"),
);
match (maj, min, pat) {
(true, _, _) => major += 1,
(_, true, _) => minor += 1,
(_, _, true) => patch += 1,
_ => unreachable!(),
};
format!("{}.{}.{}", major, minor, patch)
};
println!("Version: {}", version);
// Check for usage of -c
if matches.contains_id("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.unwrap_or_else(|| matches.get_one::<PathBuf>("spec-in").unwrap())
.display();
println!(
"Doing work using input {} and config {}",
input,
matches.get_one::<PathBuf>("config").unwrap().display()
);
}
}
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
fn main() {
// Create application like normal
let mut cmd = command!() // requires `cargo` feature
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually"))
.arg(arg!(--major "auto inc major").action(ArgAction::SetTrue))
.arg(arg!(--minor "auto inc minor").action(ArgAction::SetTrue))
.arg(arg!(--patch "auto inc patch").action(ArgAction::SetTrue))
// Arguments can also be added to a group individually, these two arguments
// are part of the "input" group which is not required
.arg(arg!([INPUT_FILE] "some regular input").value_parser(value_parser!(PathBuf)))
.arg(
arg!(--"spec-in" <SPEC_IN> "some special input argument")
.value_parser(value_parser!(PathBuf)),
)
// Now let's assume we have a -c [config] argument which requires one of
// (but **not** both) the "input" arguments
.arg(arg!(config: -c <CONFIG>).value_parser(value_parser!(PathBuf)));
let matches = cmd.get_matches_mut();
// Let's assume the old version 1.2.3
let mut major = 1;
let mut minor = 2;
let mut patch = 3;
// See if --set-ver was used to set the version manually
let version = if let Some(ver) = matches.get_one::<String>("set-ver") {
if matches.get_flag("major") || matches.get_flag("minor") || matches.get_flag("patch") {
cmd.error(
ErrorKind::ArgumentConflict,
"Can't do relative and absolute version change",
)
.exit();
}
ver.to_string()
} else {
// Increment the one requested (in a real program, we'd reset the lower numbers)
let (maj, min, pat) = (
matches.get_flag("major"),
matches.get_flag("minor"),
matches.get_flag("patch"),
);
match (maj, min, pat) {
(true, false, false) => major += 1,
(false, true, false) => minor += 1,
(false, false, true) => patch += 1,
_ => {
cmd.error(
ErrorKind::ArgumentConflict,
"Can only modify one version field",
)
.exit();
}
};
format!("{}.{}.{}", major, minor, patch)
};
println!("Version: {}", version);
// Check for usage of -c
if matches.contains_id("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.or_else(|| matches.get_one::<PathBuf>("spec-in"))
.unwrap_or_else(|| {
cmd.error(
ErrorKind::MissingRequiredArgument,
"INPUT_FILE or --spec-in is required when using --config",
)
.exit()
})
.display();
println!(
"Doing work using input {} and config {}",
input,
matches.get_one::<PathBuf>("config").unwrap().display()
);
}
}
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
fn main() {
let matches = Command::new("pacman")
.about("package manager utility")
.version("5.2.1")
.subcommand_required(true)
.arg_required_else_help(true)
.author("Pacman Development Team")
// Query subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
Command::new("query")
.short_flag('Q')
.long_flag("query")
.about("Query the package database.")
.arg(
Arg::new("search")
.short('s')
.long("search")
.help("search locally installed packages for matching strings")
.conflicts_with("info")
.action(ArgAction::Set)
.num_args(1..),
)
.arg(
Arg::new("info")
.long("info")
.short('i')
.conflicts_with("search")
.help("view package information")
.action(ArgAction::Set)
.num_args(1..),
),
)
// Sync subcommand
//
// Only a few of its arguments are implemented below.
.subcommand(
Command::new("sync")
.short_flag('S')
.long_flag("sync")
.about("Synchronize packages.")
.arg(
Arg::new("search")
.short('s')
.long("search")
.conflicts_with("info")
.action(ArgAction::Set)
.num_args(1..)
.help("search remote repositories for matching strings"),
)
.arg(
Arg::new("info")
.long("info")
.conflicts_with("search")
.short('i')
.action(ArgAction::SetTrue)
.help("view package information"),
)
.arg(
Arg::new("package")
.help("packages")
.required_unless_present("search")
.action(ArgAction::Set)
.num_args(1..),
),
)
.get_matches();
match matches.subcommand() {
Some(("sync", sync_matches)) => {
if sync_matches.contains_id("search") {
let packages: Vec<_> = sync_matches
.get_many::<String>("search")
.expect("contains_id")
.map(|s| s.as_str())
.collect();
let values = packages.join(", ");
println!("Searching for {}...", values);
return;
}
let packages: Vec<_> = sync_matches
.get_many::<String>("package")
.expect("is present")
.map(|s| s.as_str())
.collect();
let values = packages.join(", ");
if sync_matches.get_flag("info") {
println!("Retrieving info for {}...", values);
} else {
println!("Installing {}...", values);
}
}
Some(("query", query_matches)) => {
if let Some(packages) = query_matches.get_many::<String>("info") {
let comma_sep = packages.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Retrieving info for {}...", comma_sep);
} else if let Some(queries) = query_matches.get_many::<String>("search") {
let comma_sep = queries.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Searching Locally for {}...", comma_sep);
} else {
println!("Displaying all locally installed packages...");
}
}
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachable
}
}
sourcepub fn ids(&self) -> IdsRef<'_>ⓘNotable traits for IdsRef<'a>impl<'a> Iterator for IdsRef<'a> type Item = &'a Id;
pub fn ids(&self) -> IdsRef<'_>ⓘNotable traits for IdsRef<'a>impl<'a> Iterator for IdsRef<'a> type Item = &'a Id;
Iterate over Arg
and ArgGroup
Id
s via ArgMatches::ids
.
Examples
let m = Command::new("myprog")
.arg(arg!(--color <when>)
.value_parser(["auto", "always", "never"]))
.arg(arg!(--config <path>)
.value_parser(value_parser!(std::path::PathBuf)))
.get_matches_from(["myprog", "--config=config.toml", "--color=auto"]);
assert_eq!(m.ids().len(), 2);
assert_eq!(
m.ids()
.map(|id| id.as_str())
.collect::<Vec<_>>(),
["config", "color"]
);
Examples found in repository?
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
pub fn from_matches(matches: &ArgMatches) -> Vec<(clap::Id, Self)> {
let mut values = BTreeMap::new();
for id in matches.ids() {
if matches.try_get_many::<clap::Id>(id.as_str()).is_ok() {
// ignore groups
continue;
}
let value_source = matches
.value_source(id.as_str())
.expect("id came from matches");
if value_source != clap::parser::ValueSource::CommandLine {
// Any other source just gets tacked on at the end (like default values)
continue;
}
if Self::extract::<String>(matches, id, &mut values) {
continue;
}
if Self::extract::<bool>(matches, id, &mut values) {
continue;
}
unimplemented!("unknown type for {}: {:?}", id, matches);
}
values.into_values().collect::<Vec<_>>()
}
sourcepub fn args_present(&self) -> bool
pub fn args_present(&self) -> bool
Check if any args were present on the command line
Examples
let mut cmd = Command::new("myapp")
.arg(Arg::new("output")
.action(ArgAction::Set));
let m = cmd
.try_get_matches_from_mut(vec!["myapp", "something"])
.unwrap();
assert!(m.args_present());
let m = cmd
.try_get_matches_from_mut(vec!["myapp"])
.unwrap();
assert!(! m.args_present());
sourcepub fn grouped_values_of(&self, id: &str) -> Option<GroupedValues<'_>>
Available on crate feature unstable-grouped
only.
pub fn grouped_values_of(&self, id: &str) -> Option<GroupedValues<'_>>
unstable-grouped
only.Get an Iterator
over groups of values of a specific option.
specifically grouped by the occurrences of the options.
Each group is a Vec<&str>
containing the arguments passed to a single occurrence
of the option.
If the option doesn’t support multiple occurrences, or there was only a single occurrence, the iterator will only contain a single item.
Returns None
if the option wasn’t present.
Panics
If the value is invalid UTF-8.
If id
is not a valid argument or group id.
Examples
let m = Command::new("myprog")
.arg(Arg::new("exec")
.short('x')
.num_args(1..)
.action(ArgAction::Append)
.value_terminator(";"))
.get_matches_from(vec![
"myprog", "-x", "echo", "hi", ";", "-x", "echo", "bye"]);
let vals: Vec<Vec<&str>> = m.grouped_values_of("exec").unwrap().collect();
assert_eq!(vals, [["echo", "hi"], ["echo", "bye"]]);
sourcepub fn value_source(&self, id: &str) -> Option<ValueSource>
pub fn value_source(&self, id: &str) -> Option<ValueSource>
Report where argument value came from
Panics
If id
is is not a valid argument or group id.
Examples
let m = Command::new("myprog")
.arg(Arg::new("debug")
.short('d')
.action(ArgAction::SetTrue))
.get_matches_from(vec![
"myprog", "-d"
]);
assert_eq!(m.value_source("debug"), Some(ValueSource::CommandLine));
Examples found in repository?
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
pub fn from_matches(matches: &ArgMatches) -> Vec<(clap::Id, Self)> {
let mut values = BTreeMap::new();
for id in matches.ids() {
if matches.try_get_many::<clap::Id>(id.as_str()).is_ok() {
// ignore groups
continue;
}
let value_source = matches
.value_source(id.as_str())
.expect("id came from matches");
if value_source != clap::parser::ValueSource::CommandLine {
// Any other source just gets tacked on at the end (like default values)
continue;
}
if Self::extract::<String>(matches, id, &mut values) {
continue;
}
if Self::extract::<bool>(matches, id, &mut values) {
continue;
}
unimplemented!("unknown type for {}: {:?}", id, matches);
}
values.into_values().collect::<Vec<_>>()
}
sourcepub fn index_of(&self, id: &str) -> Option<usize>
pub fn index_of(&self, id: &str) -> Option<usize>
The first index of that an argument showed up.
Indices are similar to argv indices, but are not exactly 1:1.
For flags (i.e. those arguments which don’t have an associated value), indices refer
to occurrence of the switch, such as -f
, or --flag
. However, for options the indices
refer to the values -o val
would therefore not represent two distinct indices, only the
index for val
would be recorded. This is by design.
Besides the flag/option discrepancy, the primary difference between an argv index and clap index, is that clap continues counting once all arguments have properly separated, whereas an argv index does not.
The examples should clear this up.
NOTE: If an argument is allowed multiple times, this method will only give the first
index. See ArgMatches::indices_of
.
Panics
If id
is is not a valid argument or group id.
Examples
The argv indices are listed in the comments below. See how they correspond to the clap
indices. Note that if it’s not listed in a clap index, this is because it’s not saved in
in an ArgMatches
struct for querying.
let m = Command::new("myapp")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("option")
.short('o')
.action(ArgAction::Set))
.get_matches_from(vec!["myapp", "-f", "-o", "val"]);
// ARGV indices: ^0 ^1 ^2 ^3
// clap indices: ^1 ^3
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("option"), Some(3));
Now notice, if we use one of the other styles of options:
let m = Command::new("myapp")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("option")
.short('o')
.action(ArgAction::Set))
.get_matches_from(vec!["myapp", "-f", "-o=val"]);
// ARGV indices: ^0 ^1 ^2
// clap indices: ^1 ^3
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("option"), Some(3));
Things become much more complicated, or clear if we look at a more complex combination of flags. Let’s also throw in the final option style for good measure.
let m = Command::new("myapp")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("flag2")
.short('F')
.action(ArgAction::SetTrue))
.arg(Arg::new("flag3")
.short('z')
.action(ArgAction::SetTrue))
.arg(Arg::new("option")
.short('o')
.action(ArgAction::Set))
.get_matches_from(vec!["myapp", "-fzF", "-oval"]);
// ARGV indices: ^0 ^1 ^2
// clap indices: ^1,2,3 ^5
//
// clap sees the above as 'myapp -f -z -F -o val'
// ^0 ^1 ^2 ^3 ^4 ^5
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("flag2"), Some(3));
assert_eq!(m.index_of("flag3"), Some(2));
assert_eq!(m.index_of("option"), Some(5));
One final combination of flags/options to see how they combine:
let m = Command::new("myapp")
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::SetTrue))
.arg(Arg::new("flag2")
.short('F')
.action(ArgAction::SetTrue))
.arg(Arg::new("flag3")
.short('z')
.action(ArgAction::SetTrue))
.arg(Arg::new("option")
.short('o')
.action(ArgAction::Set))
.get_matches_from(vec!["myapp", "-fzFoval"]);
// ARGV indices: ^0 ^1
// clap indices: ^1,2,3^5
//
// clap sees the above as 'myapp -f -z -F -o val'
// ^0 ^1 ^2 ^3 ^4 ^5
assert_eq!(m.index_of("flag"), Some(1));
assert_eq!(m.index_of("flag2"), Some(3));
assert_eq!(m.index_of("flag3"), Some(2));
assert_eq!(m.index_of("option"), Some(5));
The last part to mention is when values are sent in multiple groups with a delimiter.
let m = Command::new("myapp")
.arg(Arg::new("option")
.short('o')
.value_delimiter(',')
.num_args(1..))
.get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
// ARGV indices: ^0 ^1
// clap indices: ^2 ^3 ^4
//
// clap sees the above as 'myapp -o val1 val2 val3'
// ^0 ^1 ^2 ^3 ^4
assert_eq!(m.index_of("option"), Some(2));
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
sourcepub fn indices_of(&self, id: &str) -> Option<Indices<'_>>
pub fn indices_of(&self, id: &str) -> Option<Indices<'_>>
All indices an argument appeared at when parsing.
Indices are similar to argv indices, but are not exactly 1:1.
For flags (i.e. those arguments which don’t have an associated value), indices refer
to occurrence of the switch, such as -f
, or --flag
. However, for options the indices
refer to the values -o val
would therefore not represent two distinct indices, only the
index for val
would be recorded. This is by design.
NOTE: For more information about how clap indices compared to argv indices, see
ArgMatches::index_of
Panics
If id
is is not a valid argument or group id.
Examples
let m = Command::new("myapp")
.arg(Arg::new("option")
.short('o')
.value_delimiter(','))
.get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
// ARGV indices: ^0 ^1
// clap indices: ^2 ^3 ^4
//
// clap sees the above as 'myapp -o val1 val2 val3'
// ^0 ^1 ^2 ^3 ^4
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 3, 4]);
Another quick example is when flags and options are used together
let m = Command::new("myapp")
.arg(Arg::new("option")
.short('o')
.action(ArgAction::Set)
.action(ArgAction::Append))
.arg(Arg::new("flag")
.short('f')
.action(ArgAction::Count))
.get_matches_from(vec!["myapp", "-o", "val1", "-f", "-o", "val2", "-f"]);
// ARGV indices: ^0 ^1 ^2 ^3 ^4 ^5 ^6
// clap indices: ^2 ^3 ^5 ^6
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2, 5]);
assert_eq!(m.indices_of("flag").unwrap().collect::<Vec<_>>(), &[6]);
One final example, which is an odd case; if we don’t use value delimiter as we did with
the first example above instead of val1
, val2
and val3
all being distinc values, they
would all be a single value of val1,val2,val3
, in which case they’d only receive a single
index.
let m = Command::new("myapp")
.arg(Arg::new("option")
.short('o')
.action(ArgAction::Set)
.num_args(1..))
.get_matches_from(vec!["myapp", "-o=val1,val2,val3"]);
// ARGV indices: ^0 ^1
// clap indices: ^2
//
// clap sees the above as 'myapp -o "val1,val2,val3"'
// ^0 ^1 ^2
assert_eq!(m.indices_of("option").unwrap().collect::<Vec<_>>(), &[2]);
Examples found in repository?
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
fn extract<T: Clone + Into<Value> + Send + Sync + 'static>(
matches: &ArgMatches,
id: &clap::Id,
output: &mut BTreeMap<usize, (clap::Id, Self)>,
) -> bool {
match matches.try_get_many::<T>(id.as_str()) {
Ok(Some(values)) => {
for (value, index) in values.zip(
matches
.indices_of(id.as_str())
.expect("id came from matches"),
) {
output.insert(index, (id.clone(), value.clone().into()));
}
true
}
Ok(None) => {
unreachable!("`ids` only reports what is present")
}
Err(clap::parser::MatchesError::UnknownArgument { .. }) => {
unreachable!("id came from matches")
}
Err(clap::parser::MatchesError::Downcast { .. }) => false,
Err(_) => {
unreachable!("id came from matches")
}
}
}
sourceimpl ArgMatches
impl ArgMatches
sourcepub fn subcommand(&self) -> Option<(&str, &ArgMatches)>
pub fn subcommand(&self) -> Option<(&str, &ArgMatches)>
The name and ArgMatches
of the current subcommand.
Subcommand values are put in a child ArgMatches
Returns None
if the subcommand wasn’t present at runtime,
Examples
let app_m = Command::new("git")
.subcommand(Command::new("clone"))
.subcommand(Command::new("push"))
.subcommand(Command::new("commit"))
.get_matches();
match app_m.subcommand() {
Some(("clone", sub_m)) => {}, // clone was used
Some(("push", sub_m)) => {}, // push was used
Some(("commit", sub_m)) => {}, // commit was used
_ => {}, // Either no subcommand or one not tested for...
}
Another useful scenario is when you want to support third party, or external, subcommands. In these cases you can’t know the subcommand name ahead of time, so use a variable instead with pattern matching!
// Assume there is an external subcommand named "subcmd"
let app_m = Command::new("myprog")
.allow_external_subcommands(true)
.get_matches_from(vec![
"myprog", "subcmd", "--option", "value", "-fff", "--flag"
]);
// All trailing arguments will be stored under the subcommand's sub-matches using an empty
// string argument name
match app_m.subcommand() {
Some((external, sub_m)) => {
let ext_args: Vec<&OsStr> = sub_m.get_many::<OsString>("")
.unwrap().map(|s| s.as_os_str()).collect();
assert_eq!(external, "subcmd");
assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
},
_ => {},
}
Examples found in repository?
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
match matches.subcommand() {
Some(("add", args)) => Ok(Self::Add(AddArgs::from_arg_matches(args)?)),
Some(("remove", args)) => Ok(Self::Remove(RemoveArgs::from_arg_matches(args)?)),
Some((_, _)) => Err(Error::raw(
ErrorKind::InvalidSubcommand,
"Valid subcommands are `add` and `remove`",
)),
None => Err(Error::raw(
ErrorKind::MissingSubcommand,
"Valid subcommands are `add` and `remove`",
)),
}
}
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
match matches.subcommand() {
Some(("add", args)) => *self = Self::Add(AddArgs::from_arg_matches(args)?),
Some(("remove", args)) => *self = Self::Remove(RemoveArgs::from_arg_matches(args)?),
Some((_, _)) => {
return Err(Error::raw(
ErrorKind::InvalidSubcommand,
"Valid subcommands are `add` and `remove`",
))
}
None => (),
};
Ok(())
}
More examples
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
fn main() {
let matches = command!() // requires `cargo` feature
.propagate_version(true)
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
Command::new("add")
.about("Adds files to myapp")
.arg(arg!([NAME])),
)
.get_matches();
match matches.subcommand() {
Some(("add", sub_matches)) => println!(
"'myapp add' was used, name is: {:?}",
sub_matches.get_one::<String>("NAME")
),
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
fn main() {
let cmd = clap::Command::new("cargo")
.bin_name("cargo")
.subcommand_required(true)
.subcommand(
clap::command!("example").arg(
clap::arg!(--"manifest-path" <PATH>)
.value_parser(clap::value_parser!(std::path::PathBuf)),
),
);
let matches = cmd.get_matches();
let matches = match matches.subcommand() {
Some(("example", matches)) => matches,
_ => unreachable!("clap should ensure we don't get here"),
};
let manifest_path = matches.get_one::<std::path::PathBuf>("manifest-path");
println!("{:?}", manifest_path);
}
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
fn respond(line: &str) -> Result<bool, String> {
let args = shlex::split(line).ok_or("error: Invalid quoting")?;
let matches = cli()
.try_get_matches_from(&args)
.map_err(|e| e.to_string())?;
match matches.subcommand() {
Some(("ping", _matches)) => {
write!(std::io::stdout(), "Pong").map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
}
Some(("quit", _matches)) => {
write!(std::io::stdout(), "Exiting ...").map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
return Ok(true);
}
Some((name, _matches)) => unimplemented!("{}", name),
None => unreachable!("subcommand required"),
}
Ok(false)
}
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
fn main() {
let cmd = Command::new(env!("CARGO_CRATE_NAME"))
.multicall(true)
.subcommand(
Command::new("busybox")
.arg_required_else_help(true)
.subcommand_value_name("APPLET")
.subcommand_help_heading("APPLETS")
.arg(
Arg::new("install")
.long("install")
.help("Install hardlinks for all subcommands in path")
.exclusive(true)
.action(ArgAction::Set)
.default_missing_value("/usr/local/bin")
.value_parser(value_parser!(PathBuf)),
)
.subcommands(applet_commands()),
)
.subcommands(applet_commands());
let matches = cmd.get_matches();
let mut subcommand = matches.subcommand();
if let Some(("busybox", cmd)) = subcommand {
if cmd.contains_id("install") {
unimplemented!("Make hardlinks to the executable here");
}
subcommand = cmd.subcommand();
}
match subcommand {
Some(("false", _)) => exit(1),
Some(("true", _)) => exit(0),
_ => unreachable!("parser should ensure only valid subcommand names are used"),
}
}
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
fn main() {
let matches = cli().get_matches();
match matches.subcommand() {
Some(("clone", sub_matches)) => {
println!(
"Cloning {}",
sub_matches.get_one::<String>("REMOTE").expect("required")
);
}
Some(("diff", sub_matches)) => {
let color = sub_matches
.get_one::<String>("color")
.map(|s| s.as_str())
.expect("defaulted in clap");
let mut base = sub_matches.get_one::<String>("base").map(|s| s.as_str());
let mut head = sub_matches.get_one::<String>("head").map(|s| s.as_str());
let mut path = sub_matches.get_one::<String>("path").map(|s| s.as_str());
if path.is_none() {
path = head;
head = None;
if path.is_none() {
path = base;
base = None;
}
}
let base = base.unwrap_or("stage");
let head = head.unwrap_or("worktree");
let path = path.unwrap_or("");
println!("Diffing {}..{} {} (color={})", base, head, path, color);
}
Some(("push", sub_matches)) => {
println!(
"Pushing to {}",
sub_matches.get_one::<String>("REMOTE").expect("required")
);
}
Some(("add", sub_matches)) => {
let paths = sub_matches
.get_many::<PathBuf>("PATH")
.into_iter()
.flatten()
.collect::<Vec<_>>();
println!("Adding {:?}", paths);
}
Some(("stash", sub_matches)) => {
let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches));
match stash_command {
("apply", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Applying {:?}", stash);
}
("pop", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Popping {:?}", stash);
}
("push", sub_matches) => {
let message = sub_matches.get_one::<String>("message");
println!("Pushing {:?}", message);
}
(name, _) => {
unreachable!("Unsupported subcommand `{}`", name)
}
}
}
Some((ext, sub_matches)) => {
let args = sub_matches
.get_many::<OsString>("")
.into_iter()
.flatten()
.collect::<Vec<_>>();
println!("Calling out to {:?} with {:?}", ext, args);
}
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!()
}
// Continued program logic goes here...
}
sourcepub fn remove_subcommand(&mut self) -> Option<(String, ArgMatches)>
pub fn remove_subcommand(&mut self) -> Option<(String, ArgMatches)>
Return the name and ArgMatches
of the current subcommand.
Subcommand values are put in a child ArgMatches
Returns None
if the subcommand wasn’t present at runtime,
Examples
let mut app_m = Command::new("git")
.subcommand(Command::new("clone"))
.subcommand(Command::new("push"))
.subcommand(Command::new("commit"))
.subcommand_required(true)
.get_matches();
let (name, sub_m) = app_m.remove_subcommand().expect("required");
match (name.as_str(), sub_m) {
("clone", sub_m) => {}, // clone was used
("push", sub_m) => {}, // push was used
("commit", sub_m) => {}, // commit was used
(name, _) => unimplemented!("{}", name),
}
Another useful scenario is when you want to support third party, or external, subcommands. In these cases you can’t know the subcommand name ahead of time, so use a variable instead with pattern matching!
// Assume there is an external subcommand named "subcmd"
let mut app_m = Command::new("myprog")
.allow_external_subcommands(true)
.get_matches_from(vec![
"myprog", "subcmd", "--option", "value", "-fff", "--flag"
]);
// All trailing arguments will be stored under the subcommand's sub-matches using an empty
// string argument name
match app_m.remove_subcommand() {
Some((external, mut sub_m)) => {
let ext_args: Vec<OsString> = sub_m.remove_many("")
.expect("`file`is required")
.collect();
assert_eq!(external, "subcmd");
assert_eq!(ext_args, ["--option", "value", "-fff", "--flag"]);
},
_ => {},
}
sourcepub fn subcommand_matches(&self, name: &str) -> Option<&ArgMatches>
pub fn subcommand_matches(&self, name: &str) -> Option<&ArgMatches>
The ArgMatches
for the current subcommand.
Subcommand values are put in a child ArgMatches
Returns None
if the subcommand wasn’t present at runtime,
Panics
If id
is is not a valid subcommand.
Examples
let app_m = Command::new("myprog")
.arg(Arg::new("debug")
.short('d')
.action(ArgAction::SetTrue)
)
.subcommand(Command::new("test")
.arg(Arg::new("opt")
.long("option")
.action(ArgAction::Set)))
.get_matches_from(vec![
"myprog", "-d", "test", "--option", "val"
]);
// Both parent commands, and child subcommands can have arguments present at the same times
assert!(*app_m.get_one::<bool>("debug").expect("defaulted by clap"));
// Get the subcommand's ArgMatches instance
if let Some(sub_m) = app_m.subcommand_matches("test") {
// Use the struct like normal
assert_eq!(sub_m.get_one::<String>("opt").map(|s| s.as_str()), Some("val"));
}
Examples found in repository?
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
fn main() {
let matches = command!() // requires `cargo` feature
.arg(arg!([name] "Optional name to operate on"))
.arg(
arg!(
-c --config <FILE> "Sets a custom config file"
)
// We don't have syntax yet for optional options, so manually calling `required`
.required(false)
.value_parser(value_parser!(PathBuf)),
)
.arg(arg!(
-d --debug ... "Turn debugging information on"
))
.subcommand(
Command::new("test")
.about("does testing things")
.arg(arg!(-l --list "lists test values").action(ArgAction::SetTrue)),
)
.get_matches();
// You can check the value provided by positional arguments, or option arguments
if let Some(name) = matches.get_one::<String>("name") {
println!("Value for name: {}", name);
}
if let Some(config_path) = matches.get_one::<PathBuf>("config") {
println!("Value for config: {}", config_path.display());
}
// You can see how many times a particular flag or argument occurred
// Note, only flags can have multiple occurrences
match matches
.get_one::<u8>("debug")
.expect("Count's are defaulted")
{
0 => println!("Debug mode is off"),
1 => println!("Debug mode is kind of on"),
2 => println!("Debug mode is on"),
_ => println!("Don't be crazy"),
}
// You can check for the existence of subcommands, and if found use their
// matches just as you would the top level cmd
if let Some(matches) = matches.subcommand_matches("test") {
// "$ myapp test" was run
if *matches.get_one::<bool>("list").expect("defaulted by clap") {
// "$ myapp test -l" was run
println!("Printing testing lists...");
} else {
println!("Not printing testing lists...");
}
}
// Continued program logic goes here...
}
sourcepub fn subcommand_name(&self) -> Option<&str>
pub fn subcommand_name(&self) -> Option<&str>
The name of the current subcommand.
Returns None
if the subcommand wasn’t present at runtime,
Examples
let app_m = Command::new("git")
.subcommand(Command::new("clone"))
.subcommand(Command::new("push"))
.subcommand(Command::new("commit"))
.get_matches();
match app_m.subcommand_name() {
Some("clone") => {}, // clone was used
Some("push") => {}, // push was used
Some("commit") => {}, // commit was used
_ => {}, // Either no subcommand or one not tested for...
}
Examples found in repository?
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
fn main() {
let cmd = Command::new(env!("CARGO_CRATE_NAME"))
.multicall(true)
.arg_required_else_help(true)
.subcommand_value_name("APPLET")
.subcommand_help_heading("APPLETS")
.subcommand(Command::new("hostname").about("show hostname part of FQDN"))
.subcommand(Command::new("dnsdomainname").about("show domain name part of FQDN"));
match cmd.get_matches().subcommand_name() {
Some("hostname") => println!("www"),
Some("dnsdomainname") => println!("example.com"),
_ => unreachable!("parser should ensure only valid subcommand names are used"),
}
}
sourceimpl ArgMatches
impl ArgMatches
sourcepub fn try_get_one<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Result<Option<&T>, MatchesError>
pub fn try_get_one<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Result<Option<&T>, MatchesError>
Non-panicking version of ArgMatches::get_one
sourcepub fn try_get_many<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Result<Option<ValuesRef<'_, T>>, MatchesError>
pub fn try_get_many<T: Any + Clone + Send + Sync + 'static>(
&self,
id: &str
) -> Result<Option<ValuesRef<'_, T>>, MatchesError>
Non-panicking version of ArgMatches::get_many
Examples found in repository?
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
pub fn from_matches(matches: &ArgMatches) -> Vec<(clap::Id, Self)> {
let mut values = BTreeMap::new();
for id in matches.ids() {
if matches.try_get_many::<clap::Id>(id.as_str()).is_ok() {
// ignore groups
continue;
}
let value_source = matches
.value_source(id.as_str())
.expect("id came from matches");
if value_source != clap::parser::ValueSource::CommandLine {
// Any other source just gets tacked on at the end (like default values)
continue;
}
if Self::extract::<String>(matches, id, &mut values) {
continue;
}
if Self::extract::<bool>(matches, id, &mut values) {
continue;
}
unimplemented!("unknown type for {}: {:?}", id, matches);
}
values.into_values().collect::<Vec<_>>()
}
fn extract<T: Clone + Into<Value> + Send + Sync + 'static>(
matches: &ArgMatches,
id: &clap::Id,
output: &mut BTreeMap<usize, (clap::Id, Self)>,
) -> bool {
match matches.try_get_many::<T>(id.as_str()) {
Ok(Some(values)) => {
for (value, index) in values.zip(
matches
.indices_of(id.as_str())
.expect("id came from matches"),
) {
output.insert(index, (id.clone(), value.clone().into()));
}
true
}
Ok(None) => {
unreachable!("`ids` only reports what is present")
}
Err(clap::parser::MatchesError::UnknownArgument { .. }) => {
unreachable!("id came from matches")
}
Err(clap::parser::MatchesError::Downcast { .. }) => false,
Err(_) => {
unreachable!("id came from matches")
}
}
}
sourcepub fn try_get_raw(
&self,
id: &str
) -> Result<Option<RawValues<'_>>, MatchesError>
pub fn try_get_raw(
&self,
id: &str
) -> Result<Option<RawValues<'_>>, MatchesError>
Non-panicking version of ArgMatches::get_raw
sourcepub fn try_remove_one<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Result<Option<T>, MatchesError>
pub fn try_remove_one<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Result<Option<T>, MatchesError>
Non-panicking version of ArgMatches::remove_one
sourcepub fn try_remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Result<Option<Values<T>>, MatchesError>
pub fn try_remove_many<T: Any + Clone + Send + Sync + 'static>(
&mut self,
id: &str
) -> Result<Option<Values<T>>, MatchesError>
Non-panicking version of ArgMatches::remove_many
sourcepub fn try_contains_id(&self, id: &str) -> Result<bool, MatchesError>
pub fn try_contains_id(&self, id: &str) -> Result<bool, MatchesError>
Non-panicking version of ArgMatches::contains_id
Trait Implementations
sourceimpl Clone for ArgMatches
impl Clone for ArgMatches
sourcefn clone(&self) -> ArgMatches
fn clone(&self) -> ArgMatches
1.0.0 · sourcefn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more