10 ms·
argp: GNU-style command line argument parser for Go
- arccy 2y ago> * multiple options can be combined: -abc is the same as -a -b -c > * option values can be separated by a space, equal sign, or nothing: -a1 -a=1 -a 1 are all equal > * options can have multiple values: -a 1 2 3 means that a is an array/slice/struct of three numbers of value [1,2,3] while convenient, one of the reasons I dislike gnu style flags is just how inconsistent they can be and annoyingly hard to parse by humans
- nine_k 2y agoUnderstandable! This is because `-a 1 2 3` assiging a = [1, 2, 3] is not GNU style. If you want that, the GNU style could be `-a "1 2 3"`. Normally `-a 1 2 3` would be a = 1, and 2 and 3 being positional arguments. A clarified way to write the same would be `-a 1 -- 2 3`.
- guappa 2y agoYeah this library is not GNU-style at all as it is.
- acmj 2y agoIn general, command-line argument parsers should just follow the GNU style. No more, no less. Deviations confuse users as it is not immediately obvious to them what rules a parser is imposing. > options can have multiple values: -a 1 2 3 means that a is an array/slice/struct of three numbers of value [1,2,3] Allowing multiple values is inconsistent because you can't tell in "./cmd -a 1 2 3" whether 2 and 3 are positional arguments or arguments for -a. This is not a GNU style. The GNU way is "./cmd -a 1 -a 2 -a 3" (or "./cmd -a 1,2,3"). This package supports that, which is good. > option values can be separated by a space, equal sign, or nothing: -a1 -a=1 -a 1 are all equal "--a=1" is a GNU style but "-a=1" is not. This is a minor issue, though. Also, does this package support "--"? Everything following "--" should be treated as positional arguments.
- cratermoon 2y agoDisagree. Go's style may not be GNU style, but it's consistent in the Go community. GNU style is not All That and a Bag of Chips.
- hnlmorg 2y agoAs a heavy user of Go tooling, I still really dislike Gos style.
- bborud 2y agoAgree. It was an unnecessary thing to do.
- naikrovek 2y agoyou two should get together and propose a better solution, with a working implementation they could adapt if needed, and integrate. talk is cheap. (I'm not saying that you're full of hot air, I'm saying that if you want to make Go's flag package better, make a proposal with good rationale behind it, include a good implementation, and see what the community says.)
- jerf 2y agoGo's flag package is covered by the backwards compatibility promise, and no large-scale change is going to be accepted. Pushing proposals to it is a waste of time. But it doesn't need to be changed. Nothing stops anyone from using any of the several argument parsers for Go. The one included in the standard library is just that and nothing more: included in the standard library. It is not privileged in any manner (beyond that brute fact), it has no access to any sort of internal standard-library only functionality that gives it access to performance external packages can't have, it isn't particularly integrated forcibly into anything else included with Go, it is not mandatory, it is not even something the community deeply believes must be used and anyone who uses alternate mechanisms is violating any sort of nebulous community standard. It's just a package. This is one of those cases where people often rather casually say "I don't like how Go handles X", or, indeed, any language with a standard library (this is not a Go-specific problem) when they really ought to say something more like "I don't like how the standard library flags package in Go handles X". But it's not the language doing it, it's the library. For a non-Go example that I've encountered in the wild, it isn't really appropriate to say "I don't like Python's GUI", referring to the built-in Tkinter binding. It's just a library. Python's got a dozen other choices, including direct bindings to every major toolkit in every major OS. It's not "Python's GUI", it's just one that ships in the standard library, not the sum total of all of Python's GUI capability.
- amelius 2y agoDoes it throw an exception when it fails to parse?
- johnisgood 2y agoAccording to the example and judging by the code at a quick glance, it does not, it seems to exit, which is unfortunate. Perhaps the author may correct me.
- latchkey 2y agoCobra https://github.com/spf13/cobra https://github.com/spf13/cobra uses https://github.com/spf13/pflag https://github.com/spf13/pflag, which supports GNU style flags. Cobra has been developed for many years now and has a ton of additional features, like automatically generating the autocompletions and has tons of unit tests. I'd just use cobra.
- imiric 2y agoCobra is certainly popular, but it has many weird edge cases and limitations. It's been a while since I've used it so I can't recall the specifics, but I do remember it being a very poor experience, both as a developer and as a user. I've had a much better experience with https://github.com/alecthomas/kong https://github.com/alecthomas/kong , and I've heard good things about https://github.com/urfave/cli https://github.com/urfave/cli , so I would recommend those over Cobra.
- latchkey 2y agoKong doesn't explicitly say it supports GNU-style, which is why I didn't mention it.
- peterldowns 2y agoThey all have their warts, but "just pick cobra/kong/cli" is what I go with these days. I'm still partial to Cobra because of the nice autocompletion scripts it generates for me so I get tab-completion for free.
- MrDarcy 2y agoThis is the correct answer. Just use Cobra, the automatic autocomplete is the best UX for users. I’ve also tried all of them. cobra is more than good enough and what issues remain in 2025 are easily and reliably worked around to be non issues.
- networked 2y agoI have used both argp and Kong. I consider them two of the best Go CLI libraries for different reasons. Kong has a full set of advanced functionality like flag groups and associating environment variables with options. It is highly useful in a larger project with a complex CLI. For a simple command-line interface, I prefer argp's small API and defaults, like exit with status 2 on bad usage. (Disclosure: I contributed this default to argp.) Kong 1.7 has a disadvantage when it comes to negative numbers. argp parses `foo --bar -1` as `foo --bar=-1` the way you expect when `--bar` takes a value, but Kong treats `-1` as a flag. Edit: Expanded the first paragraph.
- jmclnx 2y agoIf you need long options because you are running out of letters, time for a rewrite :)
- guappa 2y agoI eagerly await your feature parity curl rewrite!
- dotemacs 2y agoI'm glad that this package exists. I know of UNIX parameters, with a single hyphen & a single letter, and GNU parameters, with a double parameter and a word. But a single hyphen and then a word: *mind broken*. When I first saw that on Terraform, I was upset & conflicted. OK, I know that Java also has mental parameter options like that ('-version', note the *single* hyphen followed by, gasp, a word!), but I just dismissed it as weird enterprise-ism. Then I saw that this 'single hyphen + word' was an accepted convention for parameters, in the Go world & I was disappointed. Glad that this package is fighting the good fight.
- PhilipRoman 2y ago`find` is also notorious for its parameter style. But in my opinion programmers sometimes put too much importance on following conventions. You're not gonna go blind from looking at an incorrectly indented line. If the founding fathers of unix didn't want us creating horrifying monstrosities, they shouldn't have given us unlimited access to argv :)
- bqmjjx0kac 2y agoFun fact, `find`'s wonky argument syntax predates GNU syntax. It was part of Version 5 Unix from 1974. https://en.wikipedia.org/wiki/Find_(Unix) https://en.wikipedia.org/wiki/Find_(Unix)
- orthoxerox 2y agoAs was `dd`, another program with an unorthodox syntax.
- petepete 2y agoI used find frequently for more than a decade and it just never felt natural to me. I get there in the end but have to stop and think. With fd, a modern 'equivalent', I barely think just type. Same for grep.
- darrenf 2y ago> OK, I know that Java also has mental parameter options like that ('-version', note the *single* hyphen followed by, gasp, a word!), but I just dismissed it as weird enterprise-ism. I think "mental" is being too kind about java. $ java -version and $ java --version both work, their outputs are different, and `-version` goes to STDERR whereas `--version` goes to STDOUT.
- edoceo 2y agoI use Kong https://github.com/alecthomas/kong https://github.com/alecthomas/kong I does everything, including too complicated options.
- d_burfoot 2y agoI might be the only person in this camp, but I find the "standard" command line arguments style absolutely repulsive. I write tons of CL code, and I always use easy key=value notation (sometimes it's flag=true, which I consider to be a minor sacrifice of conciseness in favor of consistency and readability).
- bborud 2y agoIt is more important to follow a common convention than agree on which looks better. If you are lucky you get used to common conventions and spend no time annoyed with them. If you are unlucky you will struggle to let it go. Struggling to let go is a disadvantage. People who ignore convention and insist on whatever they like are never any fun to work with.
- guappa 2y agoSo to use your software one must reverse engineer your homemade parsing library because you disrespect any existing convention? I'm glad I don't use anything you wrote :)
- sandreas 2y agoInteresting. I used https://github.com/urfave/cli https://github.com/urfave/cli in the past and was pretty happy with it. However sometimes it's good to try something New :-)
- thrill 2y agoSanity!
- CamouflagedKiwi 2y agoI've become a fan of https://github.com/jessevdk/go-flags https://github.com/jessevdk/go-flags (also enjoyed structopt which is similar for Rust). I much prefer defining the flags statically on a type which stores them after rather than building it all up programmatically. Otherwise, I'm not really sure what this offers that alternatives don't, apart from the -a 1 2 3 -> [1,2,3] business which seems highly confusing and undesirable to me so I'd think of it as more of an anti-feature.
- mway 2y agoAlso a fan of go-flags, I use it by default most of the time (unless the use case is so basic that the stdlib flags usage would be sufficiently simple). I think my only real point of "frustration" (mild at best) is that flag composability isn't always possible (eg embedding/sharing common non-root flags across flag structs), IIRC struct tag eval doesn't reach nested types. Other than that though, it's one of those nice libraries that just does a thing and gets out of your way.
- CamouflagedKiwi 2y agoHmmmm I thought that sharing a common type did work in the way you would expect it to? I haven't tried embedding with it though I don't think. TBH I rarely do it much anyway, mostly the flag struct ends up being one anonymous struct which is operated on in the main package only. I do like writing custom types for parsing though - I've seen engineers do a bunch of post-hoc parsing logic which generally just ends up being messy.
- cedws 2y agoStruct tags = reflection, and reflection is nasty. They also aren't validated at compile time. Liberal use like this should be avoided.
- quacker 2y agoIn what way is reflection nasty? What compile-time validation do I actually lose by using struct tags for CLI arg parsing?
- reactordev 2y agoAside from the other comments, an ick I have is that struct tags are being abused here. Instead of providing a grouping like json, yaml, mapstructure, gorm, etc - it just goes willy nilly with struct tags like it owns the whole space. I’d like to see it grouped like… type Conf struct { Thing string `argp:”name:thing;short:t;desc:A thing you can do”` } This would follow go struct tag standards.
- braggerxyz 2y agoI really favor posix style, which is why I use pflags package for my cli Tools.
- deleted 2y ago[deleted]
- odc 2y agoThe standard flag package in Go also supports GNU style flags. https://pkg.go.dev/flag#hdr-Command_line_flag_syntax https://pkg.go.dev/flag#hdr-Command_line_flag_syntax
- declan_roberts 2y agoAssigning values like -v as an int and allowing -vvvv to be easily parsed is a great compatibility feature for existing utils.
- synergy20 2y agoi hope the below is agreed on, mycmd -h, and mycmd --help, are the same, - for single letter,-- for longer format same to mycmd -v, mycmd --version
- namuol 2y agoI have yet to find a cli args solution I enjoy using more than docopt.org
- typ 2y agoMaybe the README should mention whether reflection (the part that would disable dead-code elimnation) is used? That was a pain point for me when I had to investigate a binary bloat issue due to reflect.
- friendzis 2y agoThere's already go implementation for docopt[0] [0]: https://docopt.org/ https://docopt.org/