A Rust library for option parsing for CLI utilities.
Add this to your Cargo.toml
:
[dependencies]
getopts = "0.2"
The getopts
library is used by rustc
, so we have to be careful about not changing its behavior.
The getopts repo maintained by the rust-lang project
Home Page: https://docs.rs/getopts
License: Apache License 2.0
A Rust library for option parsing for CLI utilities.
Add this to your Cargo.toml
:
[dependencies]
getopts = "0.2"
The getopts
library is used by rustc
, so we have to be careful about not changing its behavior.
See samuela/rustybox#32 (comment). This has been a factor in https://github.com/uutils/coreutils migrating from getopts to clap.
I'm trying to port an old C application to Rust at the moment. All of the options look like -stop
; I can't find an argument parsing library in Rust which supports this format. It'd be great if getopts
could support this legacy argument style for compatibility with old applications where that style is still required.
For example cp --help
prints:
Mandatory arguments to long options are mandatory for short options too.
-a, --archive same as -dR --preserve=all
--attributes-only don't copy the file data, just the attributes
Though the current implementation of usage
would print this as:
Mandatory arguments to long options are mandatory for short options too.
-a --archive same as -dR --preserve=all
--attributes-only don't copy the file data, just the attributes
Could struct Matches
have #[derive(Debug)]
?
I'm not see it here.
If matches.opt_present
is called with a not-defined option, that should either be a compile-time error (somehow) or it should return false; currently it panics instead.
The 'contributing' section of the readme contains note that the getopts
crate is used by compiler and contributors must be careful to not break anything. Is there also consensus on what is the minimal supported version of rust compiler used to build the crate?
Example: I want to contribute by writing example code, but I'm not sure if using std::maches!()
macro is a good idea or not since it is supported only from Rust 1.42.0
.
I have err-ed on the side of caution and used different approach. But it would be nice to know what version to target so that example code do not use outdated idioms.
There are a lot of pieces to this that are uncovered in the example supplied in the docs. More examples would help to better show off how to use this
Arguments are OsString
objects. While parse()
takes an IntoIterator<Item=AsRef<OsStr>>
(which can safely accept env::args_os()
), the Matches
structure only gives out String
objects, which can only be built for UTF-8.
I don't know if this can possibly be fixed without breaking anything, but new safe methods on Matches
could certainly be introduced.
to 0.2.14
Can you take parameters that aren't flags? apt for example does...
apt install
apt upgrade
If so how does one implement that?
How does one implement their own fail for each argument? Instead of seeing
Argument to option 'S' missing
I'd like
error: no targets specified (use -h for help)
and have multiple different options for different arguments.
Like structopt.
When building rust-getopts
with tests enabled on Guix, I got the following error message:
Running .guix-tests/smoke
running 1 test
test main ... FAILED
failures:
---- main stdout ----
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: UnrecognizedOption("test-threads")', tests/smoke.rs:7:48
stack backtrace:
0: 0x7ffff7e4795b - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h190bc4e71a974fd5
1: 0x7ffff7ea2cfc - core::fmt::write::h5ab597cdd0c00db2
2: 0x7ffff7e00701 - <unknown>
3: 0x7ffff7e23c6e - <unknown>
4: 0x7ffff7e23952 - std::panicking::default_hook::hcffd5d909668cc52
5: 0x7ffff7e242ae - std::panicking::rust_panic_with_hook::h67db5ff340e389bf
6: 0x7ffff7e48277 - <unknown>
7: 0x7ffff7e47a74 - <unknown>
8: 0x7ffff7e23db2 - rust_begin_unwind
9: 0x7ffff7df5ff3 - core::panicking::panic_fmt::h4b9cfd185dab4fab
10: 0x7ffff7df6343 - core::result::unwrap_failed::h1d2e795ba7bc1e45
11: 0x5555555588f4 - core::result::Result<T,E>::unwrap::hc3c37c10d473db0e
at /tmp/guix-build-rust-1.60.0.drv-0/rustc-1.60.0-src/library/core/src/result.rs:1065:23
12: 0x5555555588f4 - smoke::main::hddc6ec79ca47762a
at /tmp/guix-build-rust-getopts-0.2.21.drv-0/getopts-0.2.21/tests/smoke.rs:7:5
13: 0x5555555588f4 - smoke::main::{{closure}}::h14f4e8f31826c44b
at /tmp/guix-build-rust-getopts-0.2.21.drv-0/getopts-0.2.21/tests/smoke.rs:6:1
14: 0x5555555588f4 - core::ops::function::FnOnce::call_once::hd8dc59dd743cb5eb
at /tmp/guix-build-rust-1.60.0.drv-0/rustc-1.60.0-src/library/core/src/ops/function.rs:227:5
15: 0x7ffff7f68723 - <unknown>
16: 0x7ffff7f688e4 - <unknown>
17: 0x7ffff7f5b80d - <unknown>
18: 0x7ffff7f7cd2f - <unknown>
19: 0x7ffff7e1c233 - <unknown>
20: 0x7ffff7bfe3aa - start_thread
21: 0x7ffff7c7ef7c - clone3
22: 0x0 - <unknown>
failures:
main
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: in phase 'check': uncaught exception:
%exception #<&invoke-error program: ".guix-tests/smoke" arguments: ("--test-threads" "16") exit-status: 101 term-signal: #f stop-signal: #f>
phase `check' failed after 0.0 seconds
command ".guix-tests/smoke" "--test-threads" "16" failed with status 101
Looks like --test-threads
isn't supported yet.
Hi. So currently it seems that getopts
does not support a parsing style that tries to match as many flags as possible, while saving the ones that it does not recognize to allow later user inspection. (such parsing style would be useful to mix up two different types of flags, one type which the user controls and the other type forwarded to a subprocess, etc.)
An example scenario: Node.js extracts flags it recognizes, which forwarding the remaining ones to the underlying v8 JavaScript engine.
It is possible to support this parsing style? Or is there some alternative way that this could be achieved?
https://doc.rust-lang.org/getopts/getopts/index.html
404
File not found
The site configured at this address does not contain the requested file.
Steps to reproduce:
Expectation:
Observed:
Sample code:
`
fn main() -> std::io::Result<()> {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
let mut opts = Options::new();
opts.reqopt("c", "config", "Configuration file", "FILE");
opts.optflag("h", "help", "Print this help menu");
let matches = match opts.parse(&args[1..]) {
Ok(m) => {
println!("Match found..." );
println!("{:?}", m.opt_str("config"));
m
}
Err(_f) => {
println!("No match found...");
}
};
Ok(())
}
`
I tried to add a --help
flag with optflag
and a required option.
I expected my_command --help
worked, but it didn't because Options::parse()
failed due to the lack of the required option.
let mut opts = Options::new();
opts.optflag("h", "help", "Description");
opts.reqopt("r", "required", "Description", "TEST");
let result = opts.parse(&["--help"]);
// Failed with "Required option 'required' missing"!
assert!(result.is_ok());
So, how about have a method to add a help flag, which is an optional and makes parse()
work without a required options if it's passed?
let mut opts = Options::new();
opts.helpflag("Description");
opts.reqopt("r", "required", "Description", "TEST");
let result = opts.parse(&["--help"]);
assert!(result.is_ok());
Currently it's 1.18.
I've been working on some bugs in uutils and I think I've found a bug in how getopts handles options with dashes and underscores in the name. Check this sample program:
let args: Vec<String> = env::args().collect();
let mut opts = Options::new();
opts.optflag("", "foo_bar", "");
opts.optopt("", "reference", "", "");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(_) => { panic!("Error") }
};
matches.opt_present("foo_bar");
let result = matches.opt_str("reference").and_then(|fname| {
let mut stat = unsafe { mem::uninitialized() };
let ret = unsafe { libc::stat(fname.as_ptr() as *const _, &mut stat as *mut libc::stat) };
if ret == 0 {
println!("Stat ok");
Some(fname)
} else {
println!("FAIL!");
None
}
});
Launch the program with touch some_string; ./test --reference some_string
.
I have observed the following:
opt_str("reference")
block before the opt_present
block always works;&str
instead of fname
inside the closure always works;and_then
closure, Rust code executes correctly. Calling libc::stat fails;and_then
into a standalone program works;stat
on the same file works.This is my first attempt at writing Rust code, so I'm out of ideas on how to debug this further. It seems that fname.as_ptr()
is somehow invalid in this example.
Crates.io only has version 0.2.12 of getopts, but the documentation is about 0.2.13.
This has caused me to spend a while trying to figure out why Error wasn't implemented for Fail.
Occasionally I want to have undocumented/hidden options that do not appear in the --help list, either due to experimental status, or deprecation. I was wondering if this is currently possible, or if this is feature people would be interested in having?
In many CLI parsers, it is a common convention to use --
as a special argument which will force all subsequent arguments to be read as positional/"free". After a quick glance at documentation and code of this crate, I could not find any information on this. How does this crate currently handle the presence of --
options? If it doesn't then consider this a feature request.
Sorry for my newbie question, but I can't find a way to exit without error when the --help
flag is present and the Options
object has a required option.
extern crate getopts;
fn main() {
let args: Vec<String> = std::env::args().collect();
let mut opts = getopts::Options::new();
opts.optflag("h", "help", "print this help menu and exit");
opts.reqopt("R", "required", "Required option", "VALUE");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
// myprogram --help
println!("Error: {}", f);
print!("{}", opts.usage("Usage: myprogram [options]"));
std::process::exit(1);
}
};
if matches.opt_present("h") {
// myprogram --help --required VALUE
print!("{}", opts.usage("Usage: myprogram [options]"));
std::process::exit(0);
}
// myprogram --required VALUE
println!("Running program");
}
When using C getopt_long
a long option with optional_argument
will have a value only if --flag=value
syntax is used. --flag arg
is parsed as a flag without an argument, and a free argument (I've verified that on macOS and Linux/glibc).
getopts' optflagopt
behaves differently. It always takes the next argument as the value, even if the =
syntax is not used.
This is problematic for me, because I can't faithfully port C getopt_long
program to Rust. I also think it's a less useful behavior, because it makes it impossible to set a optflagopt
flag without a value if it's not the last/only argument.
extern crate getopts;
fn main() {
let mut o = getopts::Options::new();
o.optflagopt("", "value", "", "");
let m = o.parse(&["--value", "foo", "bar"]).unwrap();
println!("with space {:?} + {:?}", m.opt_str("value"), m.free);
let m = o.parse(&["--value=foo", "bar"]).unwrap();
println!("with = {:?} + {:?}", m.opt_str("value"), m.free);
}
This prints:
with space Some("foo") + ["bar"]
with = Some("foo") + ["bar"]
I'd prefer it to parse as:
with space None + ["foo", "bar"]
with = Some("foo") + ["bar"]
Could we move them under tests/
?
Rust 1.18 can build v0.2.19 but not v0.2.21 Does it considered as a braking change?
I can't seem to find a way to add a positional argument. i.e I don't want to pass a flag.
my_cmd foo
instead of my_cmd -v value
Is it possible?
I've bumped into some weird behaviour in another project whereas the use of an optflagopt
option seemed to render unexpected behaviour of the option not being properly parsed.
I decided to come to the source and I extended the mod.rs test to show that something was amiss
pecastro@de5e4db
I've managed to make the test panic when you use an optflagopt
in combination with other options.
Initial investigations from debugging the test show that the vals Vec of the Matches struct will have a Vec with Given
rather than the option value specified and that is what's causing the return of None and triggering the panic.
self.vals:
[[(0, Val("foo"))], [(1, Val("bar"))], [], [(2, Given)]]
I am not entirely sure if I missed something in the documentation but is there anyway to catch multiple arguments for a matching option? For example in prog -n file1.txt file2.txt
, only file1.txt
will be put into a vector for opt_strs
in the matching option -n
and file2.txt
will be in free
. Is it possible to catch all arguments following an option with getopts?
We've accumulated some changes recently. It would be good to publish a new patch to crates.io
. I'm happy to do this, but thought I'd just flag it first.
Issue by pnkfelix
Thursday May 15, 2014 at 08:12 GMT
For earlier discussion, see rust-lang/rust#14223
This issue was labelled with: A-libs in the Rust repository
Sample program:
extern crate getopts;
use getopts::{optopt,optflagopt,getopts};
use std::os;
fn main() {
let args = os::args();
let opts =
[optopt( "o", "output", "set output file name", "NAME"),
optflagopt("a", "attrib", "set attribute", "KEY=VALUE")];
let matches = match getopts(args.tail(), opts) {
Ok(m) => { m }
Err(f) => { fail!(f.to_err_msg()) }
};
let output = matches.opt_str("o");
let keyval = matches.opt_str("a");
println!("output: {}", output);
println!("attrib: {}", keyval);
}
Here is a transcript illustrating some interesting invocations
% rustc /tmp/g.rs
% ./g --output=hm
output: Some(hm)
attrib: None
% ./g --attrib
output: None
attrib: None
% ./g --attrib hi
output: None
attrib: Some(hi)
% ./g --attrib hi=world
output: None
attrib: Some(hi=world)
% ./g -a=hi=world
output: None
attrib: Some(=hi=world)
% ./g -a hi=world
output: None
attrib: Some(hi=world)
% ./g --attrib=hi=world
output: None
attrib: Some(hi)
%
I think that --attrib hi=world
and --attrib=hi=world
should be treated as equivalent inputs.
From skimming getopts, this should be relatively easy to fix by replacing the call to split('=')
with splitn('=', 1)
.
I used getopts to create an .optopt() with a fairly long description string, and was surprised to see that when I printed the usage, my program panicked with a "... longer than limit!" error message from getopts. I haven't experimented to see what the maximum allowed string length is yet, but I'm surprised that this wasn't documented in .optopt(). Also it would be nice if the library was smart enough to print a multiline usage message instead of panicking.
std::os::args
is deprecated in favor of std::env::args
, which returns an Iterator<OsString>
. getopts should include a parse function that accepts this iterator directly, rather than requiring boilerplate to convert it to a Vec<String>
.
If you have an optopt
option (e.g., --help
) then you can have an argument with either a space or an equals sign (--help foo
or --help=foo
). However, optflagopt
requires the =
form (--help=foo
works but --help foo
is treated the same as --help
), and this is not documented (and furthermore the help message does not indicate the =
form is required, it looks like --help [TOPIC]
, not --help[=TOPIC]
or --help=[TOPIC]
).
Given this Rust program:
extern crate getopts;
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let matches = getopts::Options::new().parse(args);
}
The following invocation will create a panic:
$ ./demonstrate_bug -
thread '<main>' panicked at 'index out of bounds: the len is 1 but the index is 1', src/main.rs:1
This is using version getopts 0.2.4 with rustc 1.0.0-nightly (6c065fc8c 2015-02-17).
/Users/uh/.cargo/registry/src/github.com-1ecc6299db9ec823/getopts-0.2.9/src/lib.rs:797:7: 797:56 error: stability attributes may not be used outside of the standard library
/Users/uh/.cargo/registry/src/github.com-1ecc6299db9ec823/getopts-0.2.9/src/lib.rs:797 #[deprecated="use `Debug` (`{}` format specifier)"]
This is the version I used:
uh@macaron:~$ rustc --version
rustc 1.0.0-nightly (2baf34825 2015-04-21) (built 2015-04-21)
Issue by Jurily
Sunday Feb 16, 2014 at 03:30 GMT
For earlier discussion, see rust-lang/rust#12306
This issue was labelled with: in the Rust repository
On Unix, some programs run other programs. It is standard convention to pass along the tail of the command line unprocessed.
Examples:
bash -c command [args]
time command [args]
schedtool -e command [args]
chroot /newroot command [args]
Are there any plans of supporting option grouping in the style of Python's argparse module? At least for me that would be on top of the whishlist because I think thematic grouping of options on the usage output can improve readability very much.
I could imagine having a similar API as the argparse one:
...
options.optflag("v", "version", "Print program version");
let optgroup = options.add_option_group("Output options",
"Options for defining the output file and format");
optgroup.optopt("o", "outfile", "Output file", "FILE");
optgroup.optflag("c", "compress", "Compress output with GZIP");
print!("{}", opts.usage("Usage: mytool [options] <input>"));
output:
Usage: mytool [options] <input>
Options:
[...]
-v --version Print version info and exit
Output Options:
Options for defining the output file and format
-o --outfile FILE Output file (output defaults to stdin)
-c --compress Compress output with GZIP
There are other things that I like about argparse such as handling of positional arguments and the possibility allow undefined arguments, but I don't know whether there is an intention to keep getopts as simple as possible...
When using getopts to write rust coreutils, I encounter this problem.
In chmod
command, there is arguments like chmod -x file
or chmod -0700 file
, which will cause getopts return UnrecognizedOption
Of course we can add string "01234567rwx" into optflag, but that is quite weird because they are not expected to show up in opt.usage.
I'm not quite sure how getopts should be modified to deal with this situation.
basically if you do opts.opt_str("someinvalidname") the program just panics instead of opt_str returning a result
Change current enum Occur
to looks like this:
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Occur {
/// The option occurs once.
Req,
/// The option occurs at most once.
Optional,
/// The option occurs zero or more times.
Multi,
// NEW PART:
/// The option occurs 1 or more times
OneOrMore, // other name?
}
Currently the usage
method does the formatting, and there's no way to change it. So, I was trying to accomplish this:
/// Derive a formatted usage message from a set of options.
pub fn usage(&self, brief: &str) -> String {
let rows = self.usage_items();
format!("{}\n\nOptions:\n{}\n", brief,
rows.collect::<Vec<String>>().join("\n"))
}
/// Derive usage items from a set of options.
pub fn usage_items<'a>(&'a self) -> ReturnIter {
// Current usage method, except for the formatting line
}
In order to accomplish this:
Box
up the iterator. So that makes it ReturnIter = Box<__>
. Is there a way to do it without?Box<Iterator<Item=String>>
. Is there a better approach?As of Rust 1.36, those versions don't compile. This was fixed for 0.2.17 by #61. I think it would be useful to yank those versions for cargo update -Z minimal-versions
builds (rust-lang/cargo#5657).
For convenience, commands that can be used to yank all those versions.
cargo yank --vers 0.1.0
cargo yank --vers 0.1.1
cargo yank --vers 0.1.2
cargo yank --vers 0.1.3
cargo yank --vers 0.1.4
cargo yank --vers 0.2.0
cargo yank --vers 0.2.1
cargo yank --vers 0.2.2
cargo yank --vers 0.2.3
cargo yank --vers 0.2.4
cargo yank --vers 0.2.5
cargo yank --vers 0.2.6
cargo yank --vers 0.2.7
cargo yank --vers 0.2.8
cargo yank --vers 0.2.9
cargo yank --vers 0.2.10
cargo yank --vers 0.2.11
cargo yank --vers 0.2.12
cargo yank --vers 0.2.13
cargo yank --vers 0.2.14
cargo yank --vers 0.2.15
cargo yank --vers 0.2.16
Hello, the current rust-lang-nursery
organisation is considered deprecated, and the Rust Programming Language organisation is trying to consolidate managing Rust's GitHub organisations, as such we'd like you to consider moving your repository to the main rust-lang
organisation instead.
rust-lang
?You won't be able to transfer your repository directly, you'll need to transfer your repository to @Mark-Simulacrum, who will then move your repository to the rust-lang
organisation.
If you no longer intend to maintain this repository, please let us know and we will take of deprecating the project.
Issue by Kimundi
Saturday Mar 23, 2013 at 13:52 GMT
For earlier discussion, see rust-lang/rust#5516
This issue was labelled with: A-libs, E-easy in the Rust repository
It should at minimum align to number of codepoints (characters), (and now that PR #8710 has landed, it should be doing that minimum), but the only correct thing would be to align to grapheme clusters.
test case
extern mod extra;
use extra::getopts::groups;
fn main() {
let optgroups = ~[
groups::optflag("a", "apple", "apple description"),
groups::optflag("b", "banana\u00AB", "banana description"),
groups::optflag("c", "br\xfbl\xe9e", "br\xfbl\xe9e quite long description"),
groups::optflag("k", "kiwi\u20AC", "kiwi description"),
groups::optflag("o", "orange\u2039", "orange description"),
groups::optflag("r",
"raspberry-but-making-this-option-way-too-long",
"raspberry description is also quite long indeed longer than every other piece of text we might encounter here and thus will be automatically broken up"),
];
println(usage("Usage: fruits", optgroups));
}
current output:
% rustc /tmp/issue5516.rs && /tmp/issue5516 --help
warning: no debug symbols in executable (-arch x86_64)
Usage: fruits
Options:
-a --apple apple description
-b --banana« banana description
-c --brûlée brûlée quite long descripti
-k --kiwi€ kiwi description
-o --orange‹ orange description
-r --raspberry-but-making-this-option-way-too-long
raspberry description is also quite long indeed longer
than every other piece of text we might encounter here
and thus will be automatically broken up
Note that in addition to things failing to line up, it is also cutting off the end of the text for the brûlée case. That issue should also be fixed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.