11 ms·
Tell HN: Please don't print –-help to stderr in your CLI tools
Imagine you get a lengthy help description which then you pipe to less.. and you only get (END) in your terminal. Turns out the author decided to print help message to stderr instead of stdout. I assume newcomers will be as confused as I was when it happened to me for the first time. GNU utils use stdout for help texts, and so should you.
- jjgreen 3y agoEven more fun, Python printed --version to stderr before 3.4, then to stdout.
- Calzifer 3y agoJava (since version 9) has -version which prints to stderr and --version which prints to stdout (also with slightly different content). Same for -showversion and --show-version and to get back on topic -help -h and -? print to stderr while --help prints to stdout. https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html https://docs.oracle.com/en/java/javase/17/docs/specs/man/jav... But since the more standard double-dash variants printing to stdout where added with Java 9 I would actually laud it as good backward compatibility.
- deleted 3y ago[deleted]
- dredmorbius 3y agoThere's a case where this might be valid, which is where a command-line invocation is incorrect and a utility provides help as part of an error message. In that case, writing to stderr is justifiable. (Of course, an alternative argument is that commands should fail silently but emit a nonzero return value.) When invoked directly, as with '-h' '--help', etc., help output should write to stdout, and not stderr. StackOverflow has tackled this question, 2nd response follows the course I suggest: <https://stackoverflow.com/questions/1068020/app-help-should-go-to-stdout-or-stderr https://stackoverflow.com/questions/1068020/app-help-should-...> And in this case, the first response: <https://stackoverflow.com/questions/2199624/should-the-command-line-usage-be-printed-on-stdout-or-stderr https://stackoverflow.com/questions/2199624/should-the-comma...> I'm looking for any specific guidance from, e.g., GNU but am not finding any.
- jolmg 3y ago> In that case, writing to stderr is justifiable. More than justifiable, I'd say it's the correct thing to do in that case. Otherwise, the caller (which can be another script) may end up working with the help message thinking it was the output it expected. The whole rule should be something like "Print to stdout if it's part of what's asked by the caller. Print to stderr if it wasn't asked but the user should know about it." So outputting it to stdout should happen when it's asked via --help, and outputting it to stderr should happen when it's part of an error.
- anderskaseorg 3y agoSpecific guidance from GNU: https://www.gnu.org/prep/standards/html_node/_002d_002dhelp.html https://www.gnu.org/prep/standards/html_node/_002d_002dhelp.... > The standard --help option should output brief documentation for how to invoke the program, on standard output, then exit successfully.
- rlpb 3y agoI think you missed the point. The guidance you quote doesn't cover the case described.
- dredmorbius 3y agoIMO it does.
- jakewins 3y agoCan you be explicit with what they are missing, I’m clearly missing it as well? OP says please have —help post to stdout, GNU guidance posted above says exact same thing?
- tlamponi 3y ago> Can you be explicit with what they are missing, I’m clearly missing it as well? There are two cases when a CLI program can print its usage 1. when the `--help` option, or often also the short-option `-h`, is passed to the program 2. When the user passes a wrong option to the program, where first the error is printed and then often also the general usage. For 1. the output always should be on stdout, but for 2. the error should be on stderr, and it might be warranted that in that case the usage might be printed on stderr too, so that all is on the same stream. Doing 2. is not a must though, one can also go for an output like: > error message > Try 'program-name --help' for more information This avoids "hiding" the actual error in the often rather big amount of usage-text while still hinting how to get information about what options the program expects and/or accepts.
- 3np 3y agoFWIW: foo --help 2>&1 | less
- galdosdi 3y agoIn the meantime until every tool is rewritten to account for your recommendation, just add 2>&1 and stderr will redirect to stdout, so you can easily pipe it to other stuff
- teraflop 3y agoOr just use "|& less" to do the same thing more succinctly.
- foresto 3y ago...if you happen to be using bash.
- lolinder 3y agoOr zsh: https://zsh.sourceforge.io/Doc/Release/Shell-Grammar.html#Simple-Commands-_0026-Pipelines https://zsh.sourceforge.io/Doc/Release/Shell-Grammar.html#Si... Fish just uses a different order (&|): https://fishshell.com/docs/current/language.html#piping https://fishshell.com/docs/current/language.html#piping
- vdfs 3y agoAh bummer, every command i run need to be backward compatible with Bell Labs first release
- eesmith 3y agoUnlikely. Pipes weren't added until Version 3 Unix. https://en.wikipedia.org/wiki/Pipeline_(Unix)#History https://en.wikipedia.org/wiki/Pipeline_(Unix)#History
- SoftTalker 3y agoYes, errors (and perhaps debug messages, diagnostics, etc.) should go to stderr. The output of --help is not an error message, it's the legitimate and expected output of the program when invoked with that argument.
- GuB-42 3y agoprint --help to stdout, but if the usage is part of an error (ex: because of bad arguments), then print it to stderr. Many tools, for consistency or for laziness always print usage to stderr. But it is better than always printing it to stdout. Errors should never go to stdout, and paging stderr can easily be done with 2>&1. Edit: and maybe, if your --help output is several pages long, consider leaving out the details to a manpage.
- NoZebra120vClip 3y agoWhat's a page? I set all my terminals to 22x23. Will --help run a few quick ioctls to calculate screen size? But yeah, agree. It's way more preferable to have surprise output on stderr than surprises mingling with stdout, and it's good to be prepared for that. Frankly, I nearly quit piping to a pager when GUI terminal backscroll became easy and infinite.
- ilyt 3y ago> What's a page? 80x25 > I set all my terminals to 22x23. You are a very silly man and silliness should not be catered for. > Will --help run a few quick ioctls to calculate screen size? Your terminal can wrap text around just fine. If it can't, ask for refund.
- gumby 3y agoYou sound like someone who’s never programmed on an ADM-3a much less an ASR-33
- lytedev 3y agoYou got us <3
- deleted 3y ago[deleted]
- NoZebra120vClip 3y agoIn college we used to print out "one-page" ASCII art on the LPs. Naturally, it could get rather risqué. But I would just stare into them, marveling at the ingenuity. Of course I'd already been into it awhile, thanks to C64 Print Shop. Also my father produced tonnes of scratch paper in narrow strips. I found a way to weave them into a perpetually-growing "tractor-feed snake" which I placed in a padded crib and brought to grade school to show off. I would typically juggle a few bits and bobs to attract even more attention...
- LikesPwsh 3y agoHere's a funny bug caused by stderr being used for information. Windows Powershell gives you the detail of git push in scary red text. https://stackoverflow.com/questions/12751261/powershell-displays-some-git-command-results-as-error-in-console-even-though-ope https://stackoverflow.com/questions/12751261/powershell-disp...
- deleted 3y ago[deleted]
- zzo38computer 3y agoI agree this makes sense. The help text is the primary output of the program in this case, so it should be stdout. (However, if you want longer documentation then a man page might be better anyways.) You would use stderr for status messages, error messages, and other stuff that is not the primary output of the program. (In some cases, this might include help text; like another comment says, if you specified wrong arguments (not --help) then a short description might be a part of the error message.) One program that does write error messages to stdout and that annoys me significantly is Ghostscript. (Although you can tell it to write it to stderr, doing that causes all output to be written to stderr; I want output from "print", "==", etc to be written to stdout.)
- junon 3y agoDisagree here. It's also unenforceable so there isn't much point trying to make rules out of it.
- gleenn 3y agoJust because it's unenforceable doesn't mean you shouldn't make a rule. In fact it seems just the opposite, that's exactly the time to make a rule. If it were enforceable you wouldn't need a rule, you could just enforce it and have it be true.
- junon 3y agoIt takes one popular tool breaking convention to make the rule obsolete. There's no point.
- burnished 3y agoIts probably better to measure rules by success rate than pass/fail. One popular tool breaking convention sounds like one popular exception, which is probably better than no convention.
- verandaguy 3y agoAgree or not (i don’t), we have loads of unenforceable conventions in software. Hell, if this field is known for anything at all, it’s people getting worked up over subtle deviations from longstanding conventions.
- phyzome 3y agoIf you used --help, then decided to pipe it to less, and it disappeared, then you can't have been confused for too long. But agreed that an explicit --help should print to stdout. However, if you used the tool incorrectly (passed the wrong args) and you expected the usage information to go to stdout rather than stderr, I would disagree vehemently. stdout is (generally) for parseable information, whereas stderr is kind of a garbage bin of everything else.
- _kst_ 3y ago"But agreed that an explicit --help should print to stderr." I think you meant stdout here, not stderr.
- phyzome 3y agoFixed, thanks!
- ygouzerh 3y agoI love this answer! Indeed, we cannot put --help because sometimes the help appears when we put wrong arguments, so we should output it to stderr, so we can see that we made a mistake
- zamalek 3y agoI disagree. stderr is a misnomer, in modern usage it has effectively become stdlog/stdinfo. The only thing that should go to stdout is the result of the program. For example, many programs will print usage/help when used incorrectly. Imagine you upgrade the "read_reactor" tool, and your usage in your "control_reactor" becomes invalid - suddenly you're piping help message data to the control rods. By sending it to stderr instead, no bogus data would be piped and, as a bonus, you would see the help message after invoking your script because (as you have experienced) stderr is not piped by default. If you want to send it to less: read_reactor -h 2>&1 | less
- oasisbob 3y ago> Imagine you upgrade the "read_reactor" tool, and your usage in your "control_reactor" becomes invalid As others have noted, that's an error which shouldn't go to stdout. But help text is not an error. It's arguably the expected and primay output of the help function.
- School-Cotton 3y agoWhen passing dash dash help, the help is the output of the program, so it should go to stdout. When help is printed because the invocation was invalid, it should go to stderr. This is what most programs do, btw.
- recursive 3y agoModern usage is a misnomer. When invoked with --help, help is the result of the program.
- benatkin 3y agoI disagree, the program's purpose isn't to show the help. Asking directly for help is one of the things in the path to getting desired output, along with getting an error. If you're following such and such standards that says it should go to stdout, it should go to stdout though. I don't take that as a given. I agree with this remaining open after all of these years: https://github.com/commandlineparser/commandline/issues/399 https://github.com/commandlineparser/commandline/issues/399 OP should add 2>&1 before the pipe or replace the pipe with |& (bash) or &| (fish)
- oasisbob 3y agoThis feels like an easy one. Not quite the same, but I really dislike programs which log status updates and more fundamental output to the same place. IIRC, ffmpeg is like this with everything going to stderr, making metadata parsing more difficult than it needs to be.
- duskwuff 3y ago> IIRC, ffmpeg is like this with everything going to stderr, making metadata parsing more difficult than it needs to be. If you're trying to parse metadata, ffprobe has a set of options for structured output to stdout. Parsing this will be dramatically easier than whatever you're doing. ffprobe -print_format json -show_format -show_streams example.mp4 (There's more -show_stuff options, but they're probably more detailed than you want. Run ffprobe --help for details.)
- mdaniel 3y ago> Run ffprobe --help for details. But we all wanted to know, does it stdout or stderr? :-D (It prints help to stdout, and a bunch of junk to stderr) $ ffprobe --help 2>/dev/null Simple multimedia streams analyzer usage: ffprobe [OPTIONS] INPUT_FILE $ ffprobe --help >/dev/null ffprobe version 6.0 Copyright (c) 2007-2023 the FFmpeg developers built with Apple clang version 14.0.0 (clang-1400.0.29.202)
- werid 3y agosometimes you just want to quickly look at ffprobe's natural output but the file have a lot of metadata or subtitles or whatever, and the stuff you want to look at is printed up on top, so the natural way is to pipe it to less or a file. but no, you have to mess with stderr because the programs natural output without using the flags is an error apparently.
- somat 3y agoIn ffmpegs defense it is designed that the video stream can go on stdout. I guess it could log to stdout if you specify an explicit file and stderr when you want the video on stdout. But sometimes being consistent is better than being convenient.
- matheusmoreira 3y agoIt depends. Standard output is for program output. Standard error is something of an unfortunate name since it's actually a side channel for all non-output messages meant for the user to read. So what's "output" anyway? Whatever the user asked the program to compute. If you pass a --help option, the help message is clearly the program's output because it's what the user asked for. If you use it incorrectly and the program prints usage information, the help message should go to standard error while the output is empty because the operation failed.
- wahern 3y agoI always write my usage printing routine to take a FILE pointer, similar to the following, static void usage(const char *arg0, FILE *fp); and then at the very end of main's getopt switch something like, case 'h': usage(argv[0], stdout); return 0; default: usage(argv[0], stderr); return EXIT_FAILURE; } By default getopt prints (to stderr) a one line message for unknown options or missing arguments, so I usually don't bother catching ':' or '?' explicitly.
- henry_flower 3y agowhat really drives me crazy is when invoked $ foo -h I get "haha, you idiot, there is no such option -h, rerun with --help" when I rerun with --help, it prints a worse than useless usage string and says "for more help, type --help-advanced"
- wruza 3y agoOr when a man page is a stub that refers you to an info page.
- SushiHippie 3y agoFor this reason I have a zsh function in my .zshrc with bat (which pages by default, if it's longer than your console height): https://github.com/sharkdp/bat#highlighting---help-messages https://github.com/sharkdp/bat#highlighting---help-messages # in your .bashrc/.zshrc/*rc alias bathelp='bat --plain --language=help' help() { "$@" --help 2>&1 | bathelp } This highlights the help output with colors so it looks nicer, works with most help outputs, as it highlights the first part which is the flag/argument in one color and the description in another color
- hsbauauvhabzb 3y agoIs there any list of do’s and don’ts for cli? Common flags such as -h are used for help, but I’m not sure what other soft rules exist and don’t want to clobber well established paradigms when coding cli interfaces.
- sureglymop 3y agoQuestion regarding this: should I print output to stdout and log to stderr? Or should only log levels Error and above go to stderr? What about structured logging? Where does that go?
- eesmith 3y agoThe logging libraries I know of let you configure the log destination, for example, to save to stderr and/or a file and/or syslog or the Windows event log, etc. Use the defaults for your logging library and support a config option.
- oefrha 3y agoNo, please DO print --help output to stderr, and exit with a nonzero status while at that. I mean, please do that if you have to make a conscious choice; there's no pointing fighting if you're using an argument parsing library. --help, when used correctly, is almost always interactive, where stdout/stderr and exit status don't matter at all. The few noninteractive uses like help2man or zsh auto parsing can trivially handle a redirect. Sure, a noob piping --help to less may be confused for a first time, that's rare and it's a good chance for them to learn about streams and redirection. That leaves accidental noninteractive usage. Sooner or later someone will call your program with dynamic arguments from another program, and if your command accepts filenames/IDs there's always a chance to encounter one that starts with '-' and contains an 'h' (a practical example: YouTube video IDs). It's very easy to forget to add -- before the unsafe argument(s), so that it's accidentally interpreted as flags. Nonempty stdout, empty stderr and zero exit status makes it way too easy to accidentally accept the output as valid, only to discover much later. This is not a theoretical concern, I've made this mistake myself and had it masked by -h behavior. A noob only need to learn redirection once, in a totally harmless setting. Meanwhile, even the most seasoned expert could forget -- in a posix_spawn. At the end of the day, this is not a big deal, but as I said, if you have to make a conscious choice, make the one that makes accidental mistakes more obvious, because humans do make mistakes. This principle applies everywhere.
- wruza 3y agoAlthough unconventional, this makes sense.
- 3836293648 3y agoNo, keep --help on stdout. There's a good chance we want to pipe it to grep or less and having to write the 2>&1 incantation is a perfect way of scaring newbies off
- bandie91 3y agouse Getopt::Long; use Pod::Usage; =pod ... your scripts documentation here... =cut GetOptions( 'help' => sub{ pod2usage(-exitval=>0, -verbose=>99); }, ) or pod2usage(-exitval=>2, -verbose=>99); =pod ... continuing here... =cut
- dingosity 3y agoThis is going to sound snotty, and I'm not really trying to be, but... Unix and its derivatives were made for people who sort of knew what they were doing. The reason you pipe exceptional events to STDERR is so the STDOUT output, if it exists, can flow into the next command in the pipe. Asking for help is an exceptional event. If you want the error output of a Unixish (linux, macos, solaris, etc.) machine running bash to be lessable, re-direct it to STDOUT with `2>&1`. You probably shouldn't be touching the shell if you don't know what that does. These tools were developed assuming the users would have a basic understanding of the system they were running on. The GNU Project has published tools of varying quality, based on who was around to write the tool, debug it, give feedback, etc. It is not the exemplar of high quality software. (But it's far from crap.) The important bit about GNU (and any other software) is that it was written to adhere to their uses. Other people have different requirements. Telling people to "write your software like GNU writes their software" is to misunderstand personal agency and one of the major points of open source software. Your comments sound like you're saying "Software freedom means you're free to write software the way I want you to write software." No thank you.
- psd1 3y agoI am ambivalent. I see the value in what you're saying, and we owe so much to the ad-hoc accumulation of what we now call the gnu toolset. On the other hand, a system that has been designed coherently is much nicer to use.
- dingosity 3y agoI think this might be the crux of my discomfort with the OP's exhortation we should all adhere to his preferences. Unix and it's derivatives are great because there's a long history of people trying to do things, finding it hard and then slathering on a layer of functionality which is invoked through abstractions that are novel and probably inconsistent with those abstractions that came before. You don't need to ask anyone's permission and you won't find people saying "meh. you shouldn't do it that way." (okay. maybe a few, but you can ignore them. The Unix(tm) police won't show up to cart you away like what happens with VMS.) But the flip side of this is, yes, cruft.
- devoutsalsa 3y ago2>&1
- stabbles 3y agoIn Bash, just use `tool --help |& less` by default :) Saves a few characters compared to 2>&1
- blueflow 3y agoUse: asdf --help 2>&1 | less Even better would it be if programs did it like git and open their own manpage upon --help.
- fernandotakai 3y agoi just found out in this thread that you can use |& instead for newer bash/zsh versions, which is so much better than trying to remember 2>&1.
- deleted 3y ago[deleted]
- tremon 3y agoOh please no. If I wanted a manpage, I would have typed man git, that's just as easy to type. I use tool --help to get a quick cheat sheet of available options. Opening a man page that I didn't ask for changes my context away from the shell I was working in. Please don't force context switches on unsuspecting users.
- hexo 3y agoPlease learn to redirect output. Printing help to stderr will not mess up piped commands, instead you'd know right away that somethings up.
- dwheeler 3y agoThis always works for some foo: foo --help 2>&1 | less I'm not sure this is good advice. Many want to show usage info when there's an argument error, and you want to reuse the help code with minimal complexity.
- rini17 3y agoI prefer that I don't need to figure it all out - that the tools pipe lengthy --help to $PAGER themselves. Or open manpage like git does. I don't think this is ever used in noninteractive environment.
- epage 3y agoBeen really tempted to integrate PAGER support into the cli library I maintain (clap which is for Rust)
- rmholt 3y agoMy two cents, do not do that. Git invoking PAGER is tripping me up every time. For example, if I want to cross reference terminal output and --help and the PAGER hides the entire terminal output
- hn92726819 3y agoAs many others have said, please disregard this advice. OP (and others), if you're using zsh or bash, just use |& instead of |. That's all you have to do command --help |& less It's shorter than 2>&1 and it does the same thing.
- globular-toast 3y agoGood tip, but what the OP said is still valid. You shouldn't need to speculatively use |& then redo when you get interleaved rubbish.
- hn92726819 3y agoI think that's personal opinion though. IMO, stdout is used for anything that might make sense to pipe to another program. Help output doesn't generally make sense to send down the line, so don't send it to stdout. Fine if you do, but a general rule should be human consumption is sent to stderr. Also I wasn't suggesting to speculatively use |&, I was saying to always use it when adding --help, so you don't have to speculate
- figmert 3y agoOn that same note, please do not exit with non-zero when --help is passed. Requesting the help is expected, and I'm now not sure if the help did some weird stuff to output the help text, and one of those weird things failed, or someone was just too lazy and decided to exit with non-zero.
- rijoja 3y agoSo if you are admittedly a newcomer maybe you shouldn't try to tell people how to write programs? Edit: I didn't mean to be rude, but from my own experience I know that a lot of times when you don't like something it might be because that you don't understand it, and therefore it might be more fruitful to ask why something is in a particular way, and only after ask people not to do it, if that makes sense.
- rwmj 3y agoAlso please do always exit with some non-zero status on error. Looking at you, Fedora Python tools ...
- jefftk 3y agoIf you're in this situation, redirect stderr to stdout: $ tool-that-uses-stderr-for-help --help 2>&1 | less
- mdwalters 3y agoI don't see why a developer would do this, nothing failed, so why print to stderr on `--help`? I've printed help contents with an additional `one or more arguments expected` line to stderr in my code, but I wouldn't think someone would take it this far.