getopts
To build unix-style command line interfaces, you can use the getopts crate.
Here is a simple implementation of the echo
unix program:
$ ./echo -h
echo 1.0.0 - display a line of text
Usage:
./echo [SHORT-OPTION]... [STRING]...
./echo LONG-OPTION
Echo the STRING(s) to standard output.
Options:
-n do not output the trailing newline
-h --help display this help and exit
-V --version output version information and exit
$ ./echo --version
echo version: 1.0.0
$ ./echo Hello, World!
Hello, World!
This is a simplified version of the echo
implementation by
uutils.
It is also possible to use options instead of flags, such that values can be passed to the program:
// testopt.rs
#![feature(rustc_private)]
#![feature(collections)]
#![feature(env)]
extern crate getopts;
use std::env;
fn main() {
let args: Vec<String> = env::args().map(|x| x.to_string())
.collect();
let opts = [
getopts::optflag("a", "long_a", ""),
getopts::optflag("b", "long_b", ""),
getopts::optopt("c", "long_c", "", "VALUE"),
//^ Use `optflagopt` if the argument should be optional.
// Use `reqopt` if the option is required.
// Use `optmulti`, `optflagmulti` if options can occur multiple times.
];
let matches = match getopts::getopts(args.tail(), &opts) {
Ok(m) => m,
Err(f) => {
println!("{}", f);
env::set_exit_status(1);
return;
}
};
let a = if matches.opt_present("a") {true} else {false};
let b = if matches.opt_present("b") {true} else {false};
let c = match matches.opt_str("c") {
Some(s) => s,
None => String::from_str(""),
};
//^ Use `matches.opt_default` if you need a default (`opflagopt`).
// Use `matches.opt_count` if you need to count how many were matched
// (`*multi`).
println!("a={}, b={}, c=\"{}\"", a, b, c);
if !matches.free.is_empty() {
println!("free arguments: {:?}", matches.free);
}
}
Here are some examples how the program behaves given different combinations of arguments:
$ ./testopt
a=false, b=false, c=""
$ ./testopt -a -b
a=true, b=true, c=""
$ ./testopt -ab
a=true, b=true, c=""
$ ./testopt -c
Argument to option 'c' missing.
$ ./testopt -c value
a=false, b=false, c="value"
$ ./testopt -c=value
a=false, b=false, c="=value"
$ ./testopt -cvalue
a=false, b=false, c="value"
$ ./testopt arg
a=false, b=false, c=""
free arguments: [arg]
$ ./testopt -a arg
a=true, b=false, c=""
free arguments: [arg]
$ ./testopt -c value arg
a=false, b=false, c="value"
free arguments: [arg]
$ ./testopt -a -- -b
a=true, b=false, c=""
free arguments: [-b]
$ ./testopt -a -
a=true, b=false, c=""
free arguments: [-]