Fun aside, I think -h/--help is nowadays the most widespread and accepted version in Linux/Unix-Land. A good CLI argument parser accepts both variants.
I always default to “man foo”, because of the occasional tool that when presented with -h or --help creates a file with that name; even if there’s no manpage, “man foo” will never have any undesired side effects.
Nearly every tool does have a manpage (even a basic one) thanks to Debian’s manpage policy: “Each program, utility, and function should have an associated manual page included in the same package or a dependency.… If no manual page is available, this is considered as a bug and should be reported to the Debian Bug Tracking System.”
The rare times I encounter a command-line tool that has no manpage, I’ll sometimes write one and contribute it upstream.
Of course some programs have a useless manpage that points to info. Thankfully that is pretty much limited to GNU tools which I’m lucky enough to not have to use very often.
> Fun aside, I think -h/--help is nowadays the most widespread and accepted version in Linux/Unix-Land
The most notable exception (to me) among modern tooling is the `aws` cli, which parses help as a subcommand. And if you try `--help` it just gives you an `Unkown option` response.
I'm mildly amused by the need to reserve a little bit of brain-space for the ways to ask cli tooling for help
It would be easy for the authors of this tool to fix this behaviour. Checkout `git --help` vs `git help`, both versions work. That's just being nice to the user.
Mandoc, the default manpage formatter on OpenBSD, FreeBSD, NetBSD, macOS, and some Linuxes (as well as web frontends like manpages.debian.org and man.archlinux.org), can convert manpages to Markdown, or to HTML directly: https://mandoc.bsd.lv/man/mandoc.1.html#Markdown_Output
Watch out for bloggers: they tend to make stuff up.
There are no "Posix long options" and therefore a "Posix-compliant" argument parser will not handle them just fine.
Long options set off using two dashes were popularized by the GNU utilities.
POSIX describes a getopt C library function and a getopts utility command. Neither of them specify any requirements for long options. They will not parse long options "just fine"; not without extensions for it.
In the GNU C library (and compatibles), there is a getopt_long function that supports long options; there is no attempt made to extend the POSIX getopt to handle long options.
POSIX does not have a help option convention: -h is not consistently a help option. The "Utility Syntax Guidelines" makes numerous recommendations about options; no mention is made of anything resembling long options, or that if there is a help option, it should have such and such name.
I don't know of any utility for which POSIX requires some kind of help option; it describes only the man command.
I usually refer to these as "GNU-style arguments", whether or not that's the correct terminology. The fact that Go-based utilities tend to use the `-option` style (with a single hyphen) still bothers me.
And since the article is using podman as an example: podman does have a manpage. The actual standard way of getting documentation on utilities, man podman, works just fine.
I think man pages tend to be more heavyweight than people sometimes; if I just want to see a few of the most common options to copy, it's a lot easier to have a few lines just printed out rather than having to crawl through potentially dozens of pages being piped to `less` and then open a second terminal pane if I want to look at it while I'm typing my command.
Put another way, I think `--help` is basically the CLI equivalent of generated API docs, whereas manpages are like long-form prose documentation. While you can get by with just one of them, the experience is going to be worse for certain use cases, and generally for anything beyond a certain level of complexity, your users will be better off if you provide both.
This is overly pedantic. The point is that people using POSIX (i.e. Unix-like) systems expect -h or --help to work, as a matter of convention. What the letter of POSIX-the-standard says doesn't really matter to most people.
But it’s not overly pedantic. POSIX is literally a formal standard, and that standard does not provide a mechanism for long options. Other “POSIX (i.e. Unix-like) systems” like the BSDs do not generally use long options, nor do they generally support -h as a “help” flag.
What you’re describing as a POSIX convention is really a GNU convention. But the world of POSIX consists of more than just GNU. So the grandparent post is correct.
Large, complex code written in C that has a wide API footprint will work with little or no modification among systems like GNU/Linux, Solaris and Mac OS.
The specification is online and people use it when coding, refer to it it in discussions and when filing bug reports.
It's been my experience that the maintainers of major FOSS projects take it seriously when something is reported as being at odds with POSIX.
I don't remember any recent "POSIX strictness battle"; you didn't just make that up, did you?
There was as struggle starting in the 1980's to deal with incompatibilities among large numbers of vendor-specific derivatives of Unix that were cropping up everywhere. Unix brand incompatibilities negatively affected the users, who wanted their programs (and skills) to transfer. That is more ancient history. In retrospect, it looks like the standardization effort was broadly successful.
POSIX is not exactly standing still; it has been amassing new interfaces, and vendors adapt them as specified.
When I started coding in Unix, gethostbyname was the way to resolve DNS; now you have getaddrinfo, which is more generic and can give you IPv6 and IPv4 results in the same call. Even in basic Unix functionality, there are new features: for instance, various "at" functions, like openat: open a file relative to a specified directory descriptor, rather than the current working directory. POSIX specified threads that work everywhere, shared memory that works everywhere and other things.
There is rather a struggle between "use latest stuff in POSIX" versus "have code work on older systems".
But, overall, POSIX is a huge relief.
POSIX is a big reason why you can take code written using Glibc and get it running on Musl. Or on Cygwin.
An alternative C library that has Glibc compatibility as its goal would be a lot more difficult to develop if it had to be based entirely on reverse engineering Glibc. The Glibc documentation isn't complete enough. (And, doh, that's because it expects you to refer to POSIX for the details.)
> The getopt_long() and getopt_long_only() functions first appeared in the GNU libiberty library. The first BSD implementation of getopt_long() appeared in NetBSD 1.5, the first BSD implementation of getopt_long_only() in OpenBSD 3.3. FreeBSD first included getopt_long() in FreeBSD 5.0, getopt_long_only() in FreeBSD 5.2.
So the parsing support is there. And it is used, e.g. tar aka bsdtar:
> So the parsing support is there. And it is used, e.g. tar
Yes, the parsing support is there, so software written in the GNU style does build and run correctly on BSD systems. But although you bring up tar (a command that is well known for its unusual and unconventional flag handling), it is generally the case that commands on BSD operating systems do not use long options.
Representative examples of prominent 21st century BSD software that do not use long options:
kazinator’s point, that there is no POSIX convention of using -h for help, is correct. That convention came from GNU, and while the idea has spread due to GNU’s influence, there are other prominent schools of thought in the POSIX or Unix-like ecosystem. I would certainly not agree that long options are the common case on BSD systems.
> ???? I have no idea where these came from, but my guess is that they are migrants from the wild west Windows-land, where I assume the shell won't try to expand ? into anything. Using these options will cause problems for anyone using common shells like bash, zsh, others. Don't do it.
They come from getopt() returning '?' for any unknown option, which usually ends up being the default case in your switch, but could be '?' to be explicit.
It is in the nature of bash that you can go a decade without ever figuring something out only to have your life changed by a random comment on the internet.
Is there a shortcut to reuse the result of the last command? “which java => ll $(!!)”, but the “!!” reexecutes the last command, I’d like something which doesn’t.
This is amazing! I don't think I'll use it for help (up-arrow, ctrl+w is fewer keystrokes), but I can think of many other situations where I want to substitute one word of a very long command and didn't realize it could be this easy
does the same thing. The bash manual says ^string1^string2^ is equivalent to
!!:s/string1/string2/
where / can be any delimiter, and the "final delimiter is optional if it is the last character of the event line." So, not so surprising that the third ^ is optional too.
TIL: In either of these forms, if string1 is empty, it is set to the last string1, or, "if no previous history substitutions took place, the last string in a !?string[?] search." E.g.
$ echo foofoo
foofoo
$ ^foo^
echo foo
foo
$ ^^bar
echo bar
bar
I always forget the "version" switch. Is it '-v' or '--version' or '-version', everything's just a bit different and I can never remember what needs what to tell me its version.
[edited to add] As others have reminded me, there's also simply 'version'
To be fair, when deciding how to implement CLI options, it's probably advisable to run as far away as you can from drawing any sort of inspiration from openssl. Even git looks like a paragon of UX compared to the openssl CLI.
mawk is the worst, which, given the article's claim about POSIX, is ironic, because mawk is POSIX-compliant.
$ mawk --version
mawk: not an option: --version
$ mawk --help
mawk: not an option: --help
$ mawk -W version
mawk 1.3.4 20200120
Copyright 2008-2019,2020, Thomas E. Dickey
Copyright 1991-1996,2014, Michael D. Brennan
random-funcs: srandom/random
regex-funcs: internal
compiled limits:
sprintf buffer 8192
maximum-integer 2147483647
And mawk is (was in 16.04 at least) the default version of awk on Ubuntu. How is the user supposed to know this magic incantation? ¯\_(?)_/¯
To be fair, I can see this coming out of a strict reading of POSIX: it doesn’t say a single word about GNU-style long options (though there is an implied hole where they can fit), but explicitly leaves -W with an argument as a place for implementation-defined crufties when passed to Awk (I haven’t the slightest idea why).
(Honestly I’d rather not have the convention of programs themselves handling this at all and instead have this be `ident awk` or similar, but I understand this is not going to happen.)
Ah, but you'd have to error on any even power, since of course a negative squared is positive, thus -v^2 would be v^2 and without the dash you can't be sure it's a switch.
I absolutely hate this convention. Not only is there often very little documentation about what exactly gets added in for each verbosity level, making me guess randomly and then maybe binary search to find what I need with minimal noise, its basically impossible for me to differentiate repeated characters beyond 4 without using a cursor to step though them. I don't have any opposition to fine-grained log levels, but geez, just make it `-v [VERBOSITY (default 1)]` or something sane like that.
$ go --version
[scrolls off screen]
$ go --version | less
[scrolls off screen]
$ go --version 2>&1 | less
[search for 'version' command]
$ go version
go version go1.17.2 linux/amd64
This one is actually really interesting! I would guess that it comes from electrical engineering, and specifically the signal processing side of things where filters happen. One option for filters are “notch filters” [1], and the letter “v” looks like a notch. So just think of “notching-out” a signal when you’re trying to remove something from your grip results.
Might just be that i was taken for case insensitive.
62 characters is not a lot for tools that have a lot of settings.
In the case of tools like grep, the settings are really more of a command vocabulary, and should rightly be written in their own language in a script file, like sed and awk, but grep makes some especially commonly needed ops available as a simpler command with switches for convenience. And that results in some seemingly arcane and inconsistent commandlines.
Defining how to search for something is just not a simple 2 or 3 options covers it kind of job.
By contrast, another tool with the same problem but clearly originated from a different starting idea is 'find'. It also has to have essentially a vocabulary to express your intentions in composed sentences, and it ends up with a mix of switches and words.
I'd guess that it's probably just that `-i` and `-n` were used for other options, and `-v` is the next letter and a fairly prominent sound in the word.
Perhaps it was simply an available letter, as saghm said, but I've always imagined that at least part of the origin story is that it's a mnemonic for "invert" or "negative".
I tend to dedicate -v for version data in my apps, and use a -d(ebug) flag for more verbose logging. Or even follow the VERBOSE env var convention.
With some apps it's damn near impossible to query the version, especially cross platform. I used to manage a database of that syntax with a tool called "specs".
> Honestly, in practice, I've seen many tools that support -help also allow --help and -h for those who have the muscle memory reflex for those, so it's not nearly as problematic.
$ javac --help
javac: invalid flag: --help
Usage: javac <options> <source files>
use -help for a list of possible options
“-help” being equivalent to “-h -e -l -p” is not a GNUism. It’s described by POSIX. If a utility takes the options “-a” and “-o something” and uses POSIX getopt(), then these are all equivalent:
cmd -ao arg path path
cmd -a -o arg path path
cmd -o arg -a path path
cmd -a -o arg -- path path
cmd -a -oarg path path
cmd -aoarg path path
A long time ago I filed a bug with Sun about inconsistent flags on the JDK tooling. As I recall it they fixed the sole specific example that I cited instead of reviewing them all...
Ooh, I think this might have been the one (at least the mention of rmi and MS style paths would be consistent with what I recall working on at the time):
the clever way to parse `-help` is to treat it as multiple options, but design your argument handler so that the `help` handler short-circuits and doesn't do anything except output help text and exit (i.e. it reads '-h' then calls the help handler and exits, doesn't matter if -e isn't a valid option).
Whenever I do `cmd -h` or `cmd --help`, and the command fails and asks me to type something else, I always find this a very helpful hint that cmd’s authors don’t have respect for conventions, and that I should be cautious with my expectations from then on.
I agree, but I dunno maybe this is more new school than I realize. I'm willing to accept the possibility that other people have been exposed to conventions I haven't. On my personal projects I stick to this convention though, it just feels like the right thing to do.
The first one is verbose, not version, though? Not sure if you're used to a set of utilities that doesn't intersect the ones I'm used to where -v is version. I've seen -V, though.
I agree that -V is more common. I have used a few things that use -v for version though (I think `ruby` does, which led to some confusion for me the first time I tried to pass that to `python` and instead of getting the version number found myself in a more chatty than normal python shell).
As is quite clear in this thread, there really is no unified way of doing things.
Uppercase switches also strikes me as not very intuitive, either you need to look at the help page or you have to have the same mindset as the developer.
And still, the distinction between lowercase and uppercase switches are not easy to remember.
The cat command is rather infamous for using -v to mean “visual” (as in, convert invisible characters to something visible).
But the infamy is not that it used -v for something other than “version”—I doubt that convention existed in 1983, when the complaint was made—but rather that it was a sign of the ever-growing complexity of specific Unix tools at the expense of the harmony of the whole system.
Trouble is that some competing approaches appeared around the same time in history and what is convention depends on what you happened to be exposed to.
> what are people being exposed to that uses -single-dash-long-options?
Go's 'flag' package -- although double-dash is silently accepted on the command line.
The deeper issue with 'flag' is that it rejects the BSD convention of a short/long option pair having guaranteed equivalent semantics e.g. -h/--help. The library just won't let the programmer create such a pair by means of its standard functions.
Which uses the Plan 9 convention; the system the Go creators were exposed to. A good example of competing conventions of the past rearing itself in modern tools.
A few of my college courses used OCaml, and it had lots of conventions like this that I found somewhat odd. If I remember correctly, exceptions (which were not used that often from what I could tell due to preferences for handling errors in a more algebraic manner) are named with casing like `Not_found`, which I don't even know the name for (maybe "capitalized snake-case?), I assume to try to make them resemble the capitalization scheme that sentences use. I also remember finding it quite strange to read types annotated with a space before the colon (e.g. `let x : int in`); a friend told me that this was due to OCaml's authors being French, which unlike English puts spaces in front of colons in prose. Combined with the fact that we were taught only a subset of the language (we never once learned how to use the object system for which the "O" was put in OCaml), and we were processed provided with pre-written build files for projects and not taught much how how to use the build tools, writing OCaml always felt somewhat surreal for me. Overall though, I did learn a lot from those classes, and I think it was a good choice for teaching the concepts the courses were intended to cover (especially the compilers course, which in retrospect I would have found much more tedious if course was taught in C or Java or something).
> I also remember finding it quite strange to read types annotated with a space before the colon (e.g. `let x : int in`); a friend told me that this was due to OCaml's authors being French, which unlike English puts spaces in front of colons in prose.
Maybe, but I find it more likely that they just copied math notation. In mathematics (broadly, not just theoretical CS, also analysis), the type of something is indicated with an infix `:`, like `f : A -> B` is a function from A to B. This colon conventionally has equal spacing on both sides, like a regular infix operator.
That's possible as well. I have no idea about the accuracy of my friend's claim, which is why I relayed it as hearsay rather than stating it as a fact I was sure about.
OCaml exception constructors are just term constructors in the open sum type `exn`. In OCaml, to distinguish constructors from bound variables, constructors must begin with a capital letter. Thus `let Foo = 4;;` is an error.
> This pattern is cumbersome to deal with in practice, especially in tools that use subcommands. Instead of typing foo bar -h to get help, you have to move the cursor between foo and bar to insert help: foo help bar in order to get help about the bar subcommand. Then, once you presumably know how to use it, up-arrow, remove help from between the tool and subcommand, move to the end of the line, and continue on.
This is not a pain if you are using the default readline keybindings (which ape those of Emacs): up arrow, M-b to move back one word, type 'help ', hit RET; for the next bit, up arrow, M-b M-b to move back two words (to the beginning of 'help'), M-d to delete forward one word, C-e to go to the end of the line and you're done. No doubt it's similarly easy using the vi keybindings.
That sounds complex, but really it's second nature.
> As in the case of podman above, if you know your user is asking for help, show them the damn help.
The issue there is that it doesn't know the user is asking for help, because the way one asks for help with podman is with --help; -h is meaningless to podman. Note that -h isn't always the flag for help; just off the top of my head, in several command-line tools it is the flag for human-readable file sizes.
I hate when a program tells me what I have to do. I always think "damn it program, if you know what to do, just do it already. I say what to do, and you do it".
For example when terraform tells me to run "terraform init", as if actually typing the letters on the keyboard had any benefit...
Isn't this due to some REPL-constraints or not wanting to break the way the language works? Maybe there's no way to evaluate the "exit" and "help" objects replaced by "exit()" and "help()", and that making exceptions would clutter the code. Not sure the reasoning behind it, but that's what it seems.
This is the reason. "help" and "exit" (as well as "quit") are perfectly cromulent variable names in Python. So the REPL does the best possible thing, i.e., try and evaluate the expression and shoot a message if it fails. Case in point:
>>> help = "hi"
>>> help
"hi"
>>> del help
>>> help
Type help() for interactive help, or help(object) for help about object.
Because then when there IS a variable, the help command you learned will not work.
I think anyone crying and baffled about this is fundamentally not well suited to programming. This sort of logical problem should be intuitive.
The seeming irrationality of the special case behavior is just something funny to make your mom laugh, not something that's actually illogical or inconsistent or stupid.
It doesn't know what you're trying to do, it can just make a best-effort guess, which may be wrong. Maybe you are deep inside a session, trying to inspect a variable or function called `exit` that just doesn't happen to be in scope like you expect? Exiting the process at that point could be terrible and the impact of the lost state exceed the lifetime-accumulated lost seconds that would have been saved by being "helpful".
If you really want this, consider using ipython with %autocall as your Python REPL.
Type "help", "copyright", "credits" or "license()" for more information.
>>> help
Type help() for interactive help, or help(object) for help about object.
>>>
Python tells you to type "help", but when you do it turns out that that doesn't do much. I get it, they want to make the distinction between help() and help(object), but I feel that could have done a bit more friendly.
My "favorite" one of those is Mercurial's error when you use a subcommand that you need to enable an extension for. Not only does it know the subcommand is valid, it also tells you which extension to enable. If it's gone all that way, why not enable the extension automatically?
I have been trying to google this concept of confusion for years. Finally, an article where someone has had the same thought as me about the consistency. This has been one of those things that's impossible to search for because everything routes into a technical syntax discussion (like a MAN summary page) instead.
I want to throw out there that in addition to these parameters and how you call them in different ways, the order of operations for them is also very frustrating.
FFMPEG comes to mind immediately as an example. Essentially, you call ffmpeg to convert media1 with specs and provide media2 as an output for it. I'm understanding that THIS order matters so you're applying arguments onto the input instead of trying to do something on the output for some reason.
Where it gets confusing, though, is if you want to resize and crop an image for example. You may end up with different results depending on the order you specify these operations.
Maybe this particular use case makes sense because resizing and cropping hard-coded coordinates could be confusing. However, other operations that seem like they shouldn't interfere with each other sometimes do.
It would be nice to see some type of handling so there isn't this type of confusion. Perhaps some type of --override command, otherwise default to a consistent output regardless of order.
In contrast, I can't think of any issue I've had with "ls". I like that -l -a -t -r can be combined into -latr, but it does make learning the terminal very confusing for beginners when this isn't always supported or consistent in other programs.
> Where it gets confusing, though, is if you want to resize and crop an image for example. You may end up with different results depending on the order you specify these operations.
Could you clarify, what's confusing about it? The operations in ffmpeg are sequential, unless you use advanced chaining capabilities. If you look at a crop as a substraction, and at a resampling as a multiplication, it becomes evident, how the order affects the result.
> As in the case of podman above, if you know your user is asking for help, show them the damn help.
Since (as other comments say) you can never know for sure that the user is asking for helo, the only sane way to actually implement this is to show the "usage" message on every incorrect invocation of the command.
This has two drawbacks, however:
* It makes the output of an incorrect invocation much longer. Personally, I prefer the 2-line output approach (1 line for the error, 1 explaining how to ask for help)
* You still need to have an explicit help command, because I sure as hell don't want to craft an intentionally incorrect invocation every time I want to see the usage message.
My 2 cents: just use "--help/-h" or a "help" subcommand. They are by large the most popular ways to check out usage, no need to be creative here.
This post resonated with me and the inconsistencies certainly don’t add to the already bad discoverability of CLI arguments. Personally, I find using -h/—-help the most sane way (YMMV).
And some come with dozens of man pages, several of which need to be combined to find the syntax allowed by certain commands (often also needing a help command)! OpenSSL is bad in this way.
"You: Hi! I won! Here's my ticket! Where do I collect my winnings?"
You think you are talking to the clerk that will initiate the payout but actually you are talking to the machine that made the draw.
When you try -h or --help then the result can be nice or not. In general the author gives quite a lot of pointers. However the docs are where it is at and that is from man or Help -> etc.
If the docs are provided and if you can't be arsed to read the docs then bugger off! Now this is where it gets tricky. Not all programmers are decent writers of docs nor are all potential consumers of docs decent readers.
Now OP is whittering on about incantations requesting help. They only demonstrate a few examples so eventually one of those incantations might work.
The important thing is to ensure that a request for help does one of two things: provide help or no op.
Abseil flag library has --help and --helpfull flag.
For a code base as large as Google's, using --helpfull to output every single flag that is defined in the libraries you depend on will output a huge wall of text and often not very useful.
I always had an idea to write a --helpful flag that will pipe --helpfull output to $PAGER. That's definitely more helpful than --helpfull.
I tend to avoid doing this, for reasons someone else described in a comment (https://news.ycombinator.com/item?id=30993390): some programs spit --help output to stdout, but others to stderr, so you wind up running it a second time as “my_cli --help 2>&1 | grep ...”.
In addition, if I don’t perfectly know what I’m searching for, I’ll often get the regular expression wrong. So I prefer to check the manpage first, since it’s a lot quicker to try different search strings in my pager than by repeatedly modifying my previous command string in the shell.
It took me a second to realize that this option was supposed to comprise of both the words "help" and "full". At first I was wondering if "helpfull" was a British spelling of "helpful" that I had somehow never come across below.
The long arguments are not in POSIX. They were invented by RMS having seen them in TOPS-20. (The short options come from Multics).
The other case ignored by the author is to print out a diagnostic plus help when there is a syntax error in the invocation. This works when the command arguments are few and simple, else the case cited (explain how to ask for help) is the right thing to do.
Single-dash long arguments are indeed generally bad.
Ah, maybe “invent” is too strong a word but OTOH every invention is built on something beforehand (even the wheel presumably followed rolling something heavy over logs, presumably after making the connection about circular things rolling downhill etc…)
But long options are not so complicated an idea that “invent” might be too high falutin’.
Just for fun I’ll split hairs though: TOPS-20 (and VMS) basically only had “long” options (they could be a single character of course). CP/M and DOS got their arg syntax from TOPS-10 & RSTS but we never had TOPS-10 at MIT AI.
What RMS came up with was to have both long and short, to use two dashes to disambiguate from concatenated short options, and used the = syntax (which dd, at least, already used). Then bfox put command completion into readline, which definitely was inspired by TOPS-20 command completion (itself from TENEX).
Before that we had our own OS, ITS, and most programs didnt take options because the system didn’t really have a command line at all: instead of what is called a ‘shell’ in Multics (and copied by Unix) we just used the debugger. And of course lispms, where the whole concept of command line doesn’t make sense.
By 1984 there was one Unix machine, a VAX, in the lab but nobody used it (small word size, didn’t have much software, primitive development environment compared to what we were used to) which is why rms started using it to develop GNU.
Whew. More than I thought one could write on the topic!
Honestly I can’t remember if that was the case (though it vaguely sounds correct) or if you had to complete (was that tab?).
Now ELF is ubiquitous I wish the tab command completion were built into a section of the binary rather than being in sidecar files elsewhere in the filesystem, which is fragile.
i think tab would prompt you choices to enter next. possibly configurable. iirc this was all in a module that wasn't necessarily installed if your site couldn't spare the extra Ks of diskspace :)
In the same vein, as an old unix dog, I'm very annoyed by golang's -help vs -h and --help. Given the pedigree of the creators, I really am quite puzzled as to why they took this approach. Is there some sort of injoke where -help meant -h[elp] which would therefore expand to e.g. -he, -hl, -hp, -hel, -hlp, -hep ad nauseum?
Is that so odd? The creators have a background that predate the (relatively recent - even more so when golang was created) GNU convention. A convention that is (or at least was) mostly prevalent on Linux anyway.
Personally, I'm puzzled when people act as if the GNU double dash convention is a universal standard.
-foo wasn't all that uncommon in Unix, especially before GNU. Do you remember command line options for oldschool X11 stuff? e.g. xterm -fn 7x13bold -geometry 80x32+10+50
There are tons of options that start with -f and can't be decomposed in that way [1, e.g. -framework]. They are essentially atomic options with a loose naming convention.
It took me some thoughts to realize what you wanted to say, and you are incorrect: there is no single option `-f` in cc options! `-f` is just a common prefix of hundreds of independent options, like `-fsanitize=...` (which can't be used as `-f sanitize=...`). As I've iterated before, those prefixes mostly represent broad categories of options and not hard and fast rules: `-g` for debug, `-i` for directories, `-m` for target architectures, `-W` for warnings, and `-f` for virtually everything else.
That's just how short options with arguments work in getopt POSIX land: '-oARG' is equivalent to '-o' 'ARG' just like '--option=ARG' is equivalent to '--option' 'ARG' (for GNU long options). This means that you cannot chain any other short options after one with an (optional) argument but otherwise does not cause any problems.
To be fair to Clang, the -arguments are inherited from GCC for compatibility (which perhaps inherited them from other CCs) and then extended from there in the most consistent way possible. Similarily, clang-cl supports cl.exe-style flags for drop-in compatibility.
If there are lots of long argument names and many of them are freqently used, there is not much point for shorthands though. Better to treat single-letter "shorthands" as their canonical names in that case (e.g. compilers). Of course you can still argue that all of them should have two hyphens.
The worst offenders are the ones who even put the logic in to let one know that they knew exactly what one meant, but instead of accepting it they purposely throw an error, and adding insult to injury, telling one what one should have provided.
Those people are psychopathic abusers, and for some bizarre reason seem to be drawn to computers. I haven't figured out why yet.
Like “exit” in the Python repl, Which,knowing perfectly well what you wanted to do, will bark back “use exit()”. And only now, decades later it’s actually being fixed, but you still have evil bastards complaining that it should not do what you expect.
Looks like a leaky abstraction, in which a negligible amount of time saved in development (by mapping command line options directly to identifiers) results in UX woes.
For whatever reason, the Java tools have had these from the beginning. It's rubbish but you get used to it. More recently, they have been using double hyphens for long flags. So now you don't even know which it will be! And of course, there are extra options hidden under -XX. And flags which take arguments use inconsistent separators. So a command line might look like this:
Funnily enough, find(1), one of the oldest Unix tools to still be somewhat actively used, had those from the very beginning. Although, arguably, find(1) can be considered an interpreter of a language of its own, like sed(1) and awk(1), as opposed to a utility that accepts flags.
According to Dennis Ritchie, find(1) was developed by a different group at Bell Labs which explains the difference in style. “…We were somewhat put off by the syntax of their things. However, they were clearly quite useful, and they were accepted.”
"It came from NJ" was a pejorative at Sun. Like, if you were staring at some awful piece of code in Solaris, and you were like, "who wrote this??" and asked around, and the answer you got was "it came from New Jersey", that meant it was part of SVR4.
> Why do I have to laboriously type two hypens for a readable option?
Suppose you have a CLI app that supports the following parameters:
-e extrapolate your foos
-h highlight your bars
-l line up your bazs
-p print the aforementioned as they're being processed
So you might run the CLI as:
cli -ep
cli -hp
cli -ehp
cli -lp
# a bunch of other combinations, including
cli -ehlp
# but since the order doesn't matter, also
cli -help
Do you see why that might be a problem with the short parameters?
Now, most applications would reserve -h for help, so instead you'd still end up with the following:
cli -help
# so, the user wants to
# -h get help information
# -e extrapolate your foos
# -l line up your bazs
# -p print the aforementioned as they're being processed
which does not make a lot of sense. That's why you'd normally have something like:
-e --extrapolate extrapolate your foos
-h --help get help information
-i --highlight (-i seems close enough) highlight your bars
-l --line line up your bazs
-p --print print the aforementioned as they're being processed (though this is just an example, a lot of packages also use -v --verbose)
So then there's no such confusion:
cli -ielp # makes sense, a bunch of commands
cli -help # still doesn't make (much) sense, help shorthand mixed in with arguments for data processing
cli -h # makes sense, short hand for --help
cli --help # verbose help command
cli --highlight --extrapolate --line --print # also makes sense, just more verbose
I don't get this. Why did you reserve '-h' for highlight in the first example ? And then you chose the long option form "-h/--help" to say the problem is now fixed. It seems an entirely artificial problem made by an originally bad choice. And has nothing to do with lack of double hyphens.
> I don't get this. Why did you reserve '-h' for highlight in the first example ?
Well, for the most part i wanted to show that:
cli -help
might actually be interpreted as 4 short arguments (grouped with -), instead 1 long argument (--), these are the same if you go by GNU conventions:
cli -h -e -l -p
cli -help
Thus using -help like you're offering doesn't make sense whether -h is for "help" or for "highlighting" (example of a fictional action that the CLI might support) or anything else. In practice you won't see many software packages reserving -h for anything but help, but -elp would be a stupid example.
To understand this better, consider the following in a case where the file you want to process is literally called "help" with no extension (which is valid):
cli <ARGUMENTS> <FILE_TO_PROCESS>
1) cli -h -e -l -p help # uses 4 arguments on a file called "help"
2) cli -help help # uses those same 4 arguments on a file called "help"
3) cli help # processes a file called "help" with no arguments
4) cli -h # invokes whatever is under -h, be it help/highlight or anything else
5) cli --help # the help argument, if present
6) cli --highlight help # the highlight argument, if present, on a file called "help"
With what you're offering, options 1, 2 and 3 probably wouldn't do what you expect them to, unless you reject GNU semantics.
Ok, I see this specifically a problem with GNU option collapsing, overloading help and not returning an appropriate error for invalid usage when invalid options are passed to '-h'. Frankly, if I wanted to collapse lots of options, I would either make another option simply for that (or option concatenation option like '-c') or introduce sub-commands. Better design and more human-memorizable.
But thanks for detailed response. Upvoted for explanation. :).
The first rule of writing Go CLI tools that don’t drive users insane is to use “github.com/spf13/pflag” instead of the “flag” standard library package.
Rather annoyingly that is often the only third party dependency required…
Oh, if only I could upvote this more! And even more torture and suffering is reserved for those morons who use --long-options "because they are easy to remember".
I want -h -help --help and -? to all print the usage text. The fact that so many CLI tool programmers either don't realize that this is the right thing to do, or don't bother to do it, is just part and parcel of how user-hostile most programmers are.
I’m against lowercase -h for help (pretty common, but not universal, like in -h for human-readable sizes in GNU coreutils) for the same reason as lowercase -v for version (very rare, uppercase -V is more frequent, but the Lua interpreter does use lowercase): it hogs a valuable mnemonic for a case that doesn’t really need to allow for muscle memory to develop (the best motivation and use case for short options IMO): if you are reaching for help or the version number, you’re likely already out of the flow and are actively thinking about what you’re typing, and these options don’t need to combine with others anyway.
Allowing -? would be nice, even if only to make life easier for recent DOS/Windows expatriates, but for C programs there’s an unfortunate historical accident making this awkward: POSIX getopt(3) returns the next option character on success and a question mark on error. No reason it couldn’t return something else in principle, but realistically it’s not going to change at this point in history.
Needing to get info on command line flags is not only such a common thing but also a kind of recursive problem (you can't find out what flag to pass without being able to invoke the help text in the first place) that I'd argue it's the most valuable possible recipient of a single letter mnemonic. Having a universal and short way to print out the list of options seems way more beneficial than something like human-readables sizes, which only even makes sense for a certain subset of command line tools (what would it mean to invoke `python` or `docker` with a request for "human-readable sizes?).
> you can't find out what flag to pass without being able to invoke the help text in the first place
man command
*ducks*
Man pages are not perfect, among other things because they are only useful as a quick skimmable reference for commands with a small amount of relatively simple knobs, but I do think that the tension you are referring to is best resolved by accessing the option reference through an out-of-band mechanism (even if it is actually stored in-band, such as when using the ancient ident(1) to retreive version strings).
> what would it mean to invoke `python` or `docker` with a request for "human-readable sizes"?
I will not deny my desire for a common glossary of short options (see the SysV / GNU coreutils delimited-text suite), but at the same time I don't think it's realistic for every option letter to have a single meaning throughout the whole of the system, which is how you seem to have interpreted my statement. I do think that being able to type -h instead of --help is less valuable than being able to not use a contrived second-choice letter for something else that really wants to be called -h.
I won't bother restating the whole thing here, but basically, having a giant wall of text dumped into a pager is not super ergonomic if you just want to look at a couple examples while typing. Man pages are definitely useful, but for a different type of thing.
I just experienced this scenario today with aurutils [0]. Perhaps I needed to reboot after building it, but it only gave me any insight into its syntax when I typed “aur” with no other flags.
This is part of the reason I only use long args in scripts... to make them more self-documenting and discoverable / less ambiguous. Takes a little more effort upfront, but no need to check man pages, help, etc for random single-char args later.
(This tip probably came from another HN user long ago.)
I hate the commands that pretend that the only way to bring up help is "--help" and that "-h" isn't anything. Just show the help text, you know "-h" means I want help.
Ah, another reminder of my ex-coworker who wrote a script that:
* operated on production data (rather than beta/pre-prod data, or failing if stage is not specified) by default
* did not recognize `--help/-h` as flags, but would simply ignore them and continue to run
I'm not exactly happy in my role currently, but I'm a damn sight happier not having to deal with him anymore.
and then you launch from the command line into the app’s own console starting with > where no flags work and maybe informative commands are actually function names ending in ()
And then you encounter some ancient apps without GNU readline support (oracle sqlplus and mysql, I'm looking at both of you). No history support, cursor keys emit characters on the line, literal hell when trying to quickly fix remote database...
I think this is because some tools print the usage message to stderr rather than stdout (ironically I couldn't find an example while typing up this reply). Try:
Thanks, but you’re explaining that my finger hurts because I hit it with a hammer when I’m complaining (in a kind hearted way, I hope!) that Free Software hammers have angled heads which skid off the nail sideways onto my finger.
$ zfs -h | grep help
(Edit: ah, not a very fair example, and a topical one too :)
$ podman -h
Error: pflag: help requested
See 'podman --help'
The program recognised the flag. But instead of running the intended functionality, it tells you to re-run it. And this maddening behaviour is pervasive. You already have the code processing this, you've coded the functionality to output "you wanted X, but typed Y" because apparently this is a common thing for people to do, why don't you just run X?
It appears that docker cli will also eventually remove the short option for help. Their reasoning for it is to avoid conflicts with args (eg hostname '-h') in certain subcommands.[0][1]
But I don't see why they couldn't leave the base command's short option alone-- the user intent of a bare "docker -h" (or "podman -h") seems obvious.
The worst offenders are apps that do something even though you ask for --help.
Oh you asked for --help? No worries... I won't complain about an unknown argument nor will I complain about having no arguments at all! I'll just go ahead and do whatever I think you're asking for help about even (especially) if it's destructive!
Looking at the Git history, it was recognized straight from the start, when GOption was introduced in 2004. No idea why they chose it, and if it was their own idea, or if they followed some existing convention from somewhere else...
Another disturbing pattern I've noticed is that a lot of newer command-line programs refuse to have a proper man page. Instead, they put massive dumps of preformatted text behind one of those --help flags, which has several obvious issues. In the worst of cases, the text also uses colours, with no way to remove them without piping the output thru a sed filter.
From its earliest days, Unix has used a single hyphen to introduce command options or flags, like 'ls -l', which produces the long form directory listing, and 'cat -n', which numbers the lines that it outputs.
Every author of a command makes up the conventions for these flags. The shell processes the command line, invokes the command and passes the processed words to the command as arguments. While there are standard library routines for parsing these arguments, they don't have to be used and many original Unix commands would have been written with their own parsing code.
The oldest Unix commands like 'ls', 'cp', 'rm', and 'ps' mostly take single letter arguments. Authors often allowed such single letter arguments to be stacked up: 'ls -l' means list directory contents in long form while 'ls -r' means list directory in reverse alphabetic order and 'ls -lr', 'ls -l -r', and 'ls -r -l' mean all do the same thing, list the directory contents in long form in reverse alphabetic order.
It wasn't always the case, but by now, 'ls' has over 40 or 50 single character arguments so I find myself needing to check the man page for the less common ones. There are other quirks too. Both 'tar' and 'ps' accept arguments that don't have the dash. 'ps -a' does (almost) the same thing as 'ps a'. 'tar -xv' will extract an archive, verbosely, but so will 'tar xv'. The author of these ancient Unix commands just decided to parse the command line arguments this way.
What always bothered me was the use of full words instead of single character options introduced by a single dash. The 'find' command is one of these early Unix commands (introduced 44 years ago) that does this. "find /home/joe -name 'x*y' -print" outputs every file under directory /home/joe with a name starting with x and ending in y. This very useful command has a dizzying list of uses so the author made it easier to understand by using full words after the single dashes for elements on the command line. The recent versions of 'find' also take some single character flags: "find -d /home/joe -name 'x*y' -print" does almost the same thing as the previous example in this paragraph, but it descends into directories in a depth-first order.
Compilers, with there own complex set of command line flags, options, and arguments have long used their own, offbeat, interpretations of their command lines arguments.
Most Unix commands attempt to parse their command line arguments and if they couldn't, they would print out a few lines with a compact usage description. For example 'ps -Q' is not something that the 'ps' command understands so it produces:
If this isn't enough help, one would check the man pages (with 'man ps'). I know that I saw commands written to use help when passed '-h' long ago, but around 1986 or so it wasn't common and often '-h' simply triggered the standard usage output because there was no option '-h'.
I find it hilarious that on Windows there are commands using Windows style options (ipconfig, robocopy) and Unix style options (netstat, tracert). That's probably part of the POSIX compliance. So the list of possible help options to try is even longer: "/?", "-?", "/h", "-h", "/help", "-help", and "--help". For most of the utilities distributed by MS "/?" works even if the command uses dash options, but third party utilities usually support only their "native" options.
git /?: '/?' is not a git command. See 'git --help'.
7z /?: Unsupported command
psql /?: trying to connect
And for PowerShell cmdlets you should use "help Verb-Thing" or "help Verb-Thing --Online".
Fun aside, I think -h/--help is nowadays the most widespread and accepted version in Linux/Unix-Land. A good CLI argument parser accepts both variants.
reply