question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Design discussion: how to handle --help option

See original GitHub issue

The design principle behind CommandLineParser is to mimic the behavior of the standard GNU getopt library, but the handling of the standard --help option is failing to mimic getopt correctly.

How it currently works

Currently, the --help option is really only recognized if it’s the first option passed, e.g.:

  • progname --help causes the parser to return a HelpRequestedError, which if AutoHelp=true (the default) will print the help text.
  • progname help causes the parser to return a HelpVerbRequestedError, which if AutoHelp=true will print the help text.
  • progname foo --help is handled differently depending on whether foo is a verb:
    • If foo is a verb, then the help for that verb is constructed and returned.
    • If foo is NOT a verb, then progname foo --help causes the parser to return an UnknownOptionError(“help”), which if AutoHelp=true will print the help text, and NOT print “ERROR(S): Option ‘help’ is unknown.” This is because UnknownOptionError(“help”) is explicitly filtered out of the “meaningful errors” list, and only “meaningful errors” are displayed to the user.
  • progname foo bar --help, when foo is a verb, actually does the same as progname foo --help when foo is not a verb: it returns an UnknownOptionError(“help”) which is then filtered out of the output.

How it should work

The GNU Coding Standards docs on how to handle --help are short:

The standard --help option should output brief documentation for how to invoke the program, on standard output, then exit successfully. Other options and arguments should be ignored once this is seen, and the program should not perform its normal function.

This doesn’t resolve some of the ambiguous situations. But by experimenting with standard GNU utilities and how they handle the --help option, some clear patterns emerge:

  • progname --help should print help output
  • progname --help foo should ignore the argument “foo” and print help output.
  • progname arg1 arg2 --help should ignore arg1 and arg2 and print help output. Whether arg1 and arg2 were valid options or not should be completely ignored, and the help output should not contain any errors even if arg1 and arg2 were invalid.
  • progname --input-file --help, where --input-file is an option that expects a string parameter, is a bit of a gotcha. This should NOT print help output; rather, --input-file should receive the string --help as its parameter. (You can confirm this by running multiple GNU commands on Linux, such as ls --help vs ls --quoting-style --help, and so on). More about this later.
  • progname verb --help should display the help text for the specific verb in question if verbs are being used, otherwise verb should be ignored.
  • progname verb arg1 arg2 --help should also display the help text for the specific verb in question, and not return any errors about arg1 and arg2.

The GNU standards do not specify whether -h should be taken as a short form for the long --help option. Here the behavior differs between Linux programs: some programs allow -h as a short form for --help, while others use -h as a short form for a different command (e.g., ls -h is short for ls --human-readable). The way CommandLineParser should handle this is to have a AutoHelpShortName flag (a bool), defaulting to *false. If it is true, then the -h option will be taken as a shortname for --help. AutoHelpShortName should not be a string or a char; it is not recommended to change the shortname of the auto-help parameter from -h to something else, so if you want to do that you’ll need to set AutoHelp=false and implement your own help option.

About that --input-file --help scenario

The naïve approach, of scanning the incoming arguments to look for a --help option, will fail in this scenario. What needs to happen instead is that all arguments need to be parsed, and then all options (but NOT values) need to be scanned for the --help option, and/or the -h option if AutoHelpShortName is true. If the --help option is found, then all other errors are ignored (as per the GNU docs) and the help text is printed out. (The only time errors should be printed out is if --help is not present).

What about --version?

The GNU docs for --version are similar to --help:

The standard --version option should direct the program to print information about its name, version, origin and legal status, all on standard output, and then exit successfully. Other options and arguments should be ignored once this is seen, and the program should not perform its normal function.

They go on to explain in more detail how to format the version information, but that’s not really relevant for this issue. What’s important here is that --version should be treated just like --help: it should handle --version appearing in any position in the options (except as a value to some other option), and should not return any other errors if --version is found. Also, there should be flag named AutoVersionShortName, defaulting to false, which will use the shortname -V (capital V) if it is true. (Lowercase -v is usually reserved for --verbose; the de facto standard in Linux utilities is that if --version has a shortname, it’s capital -V).

PR forthcoming

I plan to write a PR to handle --help and --version correctly, as opposed to the slightly-wrong way that CommandLineParser currently handles it. Expect that PR in the next few weeks.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:3
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
rmunncommented, Jun 4, 2020

I’ve read the origin of AutoHelp and AutoVersion, and also the discussion of why help output goes to stderr by default instead of stdout. (Which is a mistake, and CLP version 3 should swtich to stdout by default). BTW, in your comment about why version and help are directed to stderr, you say there are no drawbacks. I’ll intersperse my answer below to explain why there are drawbacks after all.

Is there a drawback of directing the version and help screen to the standard error (stderr) No, why:

Yes, there are drawbacks, as I’ll explain below.

1. The merit of writing to stderr is that the output will always be directed to the command line and **it will always be written immediately to the display device**. This means you will always see the output directed to stderr, as long as you have not reassigned stderrto another destination.

If the user is redirecting output when they call myprog --help, they have a reason for it. For example, I sometimes do someprog --help | grep -i input when the help screen is two pages long and I’m just looking for which option is used for input files. If someprog directs its help output to stderr, that becomes difficult; I have to do someprog --help 2>&1 | grep -i input instead, which is convoluted.

2. stdout is fully buffered and stderr is not buffered. In other words, stdout will flush the buffer when the programmer explicitly asks for it or when it is most convenient, **stderr writes the message immediately**.
   [ref: stdin, stdout, stderr](https://docs.microsoft.com/en-us/cpp/c-runtime-library/stdin-stdout-stderr?view=vs-2019)

The fact that stderr is unbuffered is not an advantage when it comes to handling the --help or --version options, since the correct behavior for those options is to print out some help or version text, and then exit immediately. So the end user will get the text immediately, buffering or no buffering.

BTW, you can’t actually count on stderr always being unbuffered. http://www.cplusplus.com/reference/cstdio/stderr/ says “stderr is is never fully buffered on startup. It is library-dependent whether the stream is line buffered or not buffered by default (see setvbuf).” (Emphasis mine).

3. No advantage for reassigning to stdout in windows, linux, Mac.

The someprog --help | grep foo scenario that I mentioned in point 1 is an advantage.

4. Basically stderr and stdout are two different output streams, by default consoles display them both without redirection and both are manged by OS.
   By default, they both display on the terminal(**but you can redirect them if needed**).

This is correct; either one defaults to the terminal, so that by itself is no reason to pick one over the other.

5. The Core developers classified the  help and version as  types of errors (**By Design**), and logically they can  be displayed in the standard error stream  (screen by default)

This breaks the GNU Coding Standards (here and here), and as someone else mentioned, it can break some build infrastructure that naïvely assumes that anything printed to stderr is an error. Printing the help text when --help is requested (or the version info when --version is requested) is not an error, it’s the normal behavior.

6. In custom help, you can redirect to stdout (if needed)

This at least mitigates CLP’s mistake in putting help text on stderr, because library users can fix the mistake without waiting for CLP version 3.

Summary No loss if using stderr and No gain if using stdout. Both are directed to the screen. I think it’s better to keep the output ASIS without change (By Design).

Because it breaks the GNU Coding Standards as well as most Unix users’ expectations, the default should be changed in the next major version number (where breaking changes are acceptable).

0reactions
moh-hassancommented, May 21, 2020

@rmunn Thanks for this design discussion. Just for completeness please can you look to the origin of change of AutoHelp/ AutoVersion in #87 , #200 and PR #256 . #399 for help output to console Error [Gnu comparison] (https://github.com/commandlineparser/commandline/issues/357#issuecomment-435513063) These posts will be part of our discussion to get a history related to the design.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Making feedback helpful in design discussions
Setting the stage for receiving better feedback · State the problems and constraints to help set the context. · State the objective of...
Read more >
Communication hacks for effective Design Discussions
9. Most important: Be open to criticism. Critique is an integral part of the design process to ensure a quality output. As much...
Read more >
What are good habits for designing command line ...
always handle --version and --help (even /bin/true accepts them!!) ... Show these option lists on option argument error.
Read more >
Discussions - Eberly Center
Discussions can be an excellent strategy for enhancing student motivation, fostering intellectual agility, and encouraging democratic habits. They create ...
Read more >
How to Design an Agenda for an Effective Meeting
Ask team members to suggest agenda items and include a reason why each item needs to be addressed in a team setting. If...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found