5 ms·
In 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
by acmj 1y ago
In 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 1y 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 1y agoAs a heavy user of Go tooling, I still really dislike Gos style.
- bborud 1y agoAgree. It was an unnecessary thing to do.
- naikrovek 1y 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 1y 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.
- naikrovek 1y agoYou imagined that I was saying that the existing flag stuff in the standard library should be replaced, I never suggested that. You can add better things without breaking compatibility promises. See: many, many features added since 1.0. New IP address types, slog, etc.
- jerf 1y agoPeople are not looking to "add" to the library. They don't like it at all and want to completely stop it from doing what it does. There is no proposal process that is going to make them happy. Fortunately, that is not a prerequisite for their happiness.
- acmj 1y agoWhen I use a command-line tool, I don't know and don't care if it is written in Go or not. I just want to use it the same way as most of the other traditional Unix tools. The Go style gets in the way. We would have much more consistent CLI between tools if Go had just followed the GNU style at the beginning. The same can be said to many other languages like Nim that want to reinvent command-line argument parsing with their standard libraries. https://xkcd.com/927/ https://xkcd.com/927/ came to mind.
- klodolph 1y agoCan’t you just use --long options everywhere? For, like, 95% of the tools out there, I’m going to use --long every single time. Anyway, I don’t even know the options that a program takes until I read the program docs. The program docs will tell me that the option is -host=localhost or --host=localhost or --bind-addr=localhost:8000. The other 5% are tools like ls, cp, mv. As far as I care, ancient tools are the only ones permitted to have short options that combine into a single option, like old-school getopt. Maybe a few exceptions now and then.
- cratermoon 1y agoI use short options when I'm typing at the command line, but for scripts I prefer the long options by a wide margin. It's just too painful to come back to script after some time and see a string of short options that looks like line noise barfed out of a 300 baud modem.
- treyd 1y agoYou can't expect the user to remember upfront what language the tool they're using was written in and context switch the style they're expressing their intents in based on that. The Go community has consistently shown it's not very good at making well-thought out decisions. GNU is obviously the better approach here.
- kirici 1y ago> The Go community has consistently shown it's not very good at making well-thought out decisions. Please, do name one language that has.
- urxvtcd 1y agoI think you mean "inconsistent at making good decisions", which one can expect to be quite common, but GP probably meant "consistently making bad decisions", which is different.
- kirici 1y agoI'm implying that a statement pointing at and deriding A for doing X is useless or misleading, if every alternative to A does X, arguably even more so. The precise interpretation of a given X does not matter.
- arp242 1y ago> it's consistent in the Go community. Except it's not? There are tons of flag packages in real use, because the stdlib one kind of sucks. Even the "go" tool itself works around some of its limitations (things like "go test ./... -v" won't work out of the box, since it will stop parsing flags at the first non-flag, so the go command reorders os.Args before sending it off to the flag package). Things like "-a 1 2 3" are not standard "Go style" at all. I've never seen that.
- thiht 1y ago> because the stdlib one kind of sucks It doesn’t. It’s simpler, which makes it not suck in my books. All the stuff about short vs long, grouping short flags together, allowing the last flag of a group of short flags to take an argument, allowing a flag to take multiple values, etc. is cool, but confusing and quite hard to do right. In Go it’s just -flag[=value].
- nloomans 1y agoI disagree with it being a minor issue. If I write a shell script around a program that accepts GNU-style arguments, I expect the following to be correct: ./cmd -a"$USER_CONTROLLED_DATA" A program using this package would break that assumption, introducing a bug where this user-controlled data cannot start with an '='.
- duckerude 1y agoI researched this for my own argument parser (https://github.com/blyxxyz/lexopt/issues/13 https://github.com/blyxxyz/lexopt/issues/13) and concluded that it's a minor issue. This syntax is supported by argparse and clap, the most popular argument parsers for Python and Rust respectively, and it seems to have caused almost no problems for them. It's a problem for the uutils implementation of cut, since `cut -d=` is common, but that's the only instance I could find after a long time scouring search engines and bug trackers and asking for examples. If anyone does know of other examples or other places this has been discussed I'd love to hear it though, maybe I just haven't found them. (Also, the more reliable way to write this in general is `-a "$USER_CONTROLLED_DATA"`, since that'll behave correctly if $USER_CONTROLLED_DATA is empty. As will `-a="$USER_CONTROLLED_DATA"` if you know the command supports it.)
- cb321 1y agoHa! I just said that. :-) Anyway, one other alternative for the `cut` situation is to allow either ':' or '=' to optionally separate the key and the value. Then you can say `cut -d:=` or `cut -d=:` if you wanted to use either one. This is what https://github.com/c-blake/cligen https://github.com/c-blake/cligen does (for Nim, not Go).
- duckerude 1y agoThe problem is existing shell scripts and muscle memory and command histories. `cut -d=` has always worked and works on all the other implementations so it should keep working if you switch to uutils.
- Arch-TK 1y agoUnfortunately a lot of people nowadays don't seem to notice or care and you even get weird arguments like the one about "Go style" vs "GNU style" below. I've also heard arguments about making it more "user friendly" (at the cost of any power user wanting to re-write your tool). I wouldn't mind if GNU style was consistently extended to allow annotated required arguments. But that's about it. That being said. As a rule, if your command line utility has enough positional arguments that you're forgetting which one is which, it's a badly designed command line interface. Most often it's because you're doing too much, not settling on sensible defaults for things which you shouldn't need to specify every time, or just doing something outright weird.
- mjevans 1y agoIME commands get there by expressing complexity that belongs in a full configuration file on the command line (as well / instead). It's nice if things are simple enough that a hand-full or two of flags are sufficient. However more complex programs that do more or substantially different things from traditional bytestream filter programs often do need proper configuration files.
- deleted 1y ago[deleted]
- marxisttemp 1y agoNo, command tools should follow the POSIX standards, not GNU.
- masklinn 1y agoYou're almost right. No command tools should follow the POSIX standard. A standard which all but forbids long options deserves only scorn.
- NekkoDroid 1y agoPOSIX doesn't even provide any utilities to write long opts and it also doesn't even define any long opts for basically any of its commands, so by default it is barely usable in maintainable scripts.
- greyw 1y agoPOSIX doesnt even define long opts. I conciously dont follow POSIX these days. The standard will adapt once enough pressure has built up as they mostly document existing things instead of innovate. So I need to apply pressure.
- ants_everywhere 1y agoAre you saying this because you think the GNU standard is particularly well thought out, or because it's so common that deviations are confusing in general? I'm so used to the GNU conventions that I'm not really aware of what the alternatives are or what their merits are.
- gjvc 1y agoGNU became the de-facto standard at least 20 years ago
- acmj 1y agoThe most important part is to have a standard, which doesn't need to be perfect. On argument parsing, I actually think the GNU way is the best so far. I have seen various deviations from GNU and I personally regard all of them inferior.
- deleted 1y ago[deleted]
- tdewolff 1y agoJust to clarify, the documentation was a bit outdated, but `./cmd -a 1 2 3` would not mean an array of `[1,2,3]` but exactly as you mentioned: option `a` with two positional arguments. And yes! The `--` is supported :-)