[HN Gopher] "Rules" that terminal programs follow
___________________________________________________________________
"Rules" that terminal programs follow
Author : charlieok
Score : 121 points
Date : 2024-12-12 17:09 UTC (5 hours ago)
(HTM) web link (jvns.ca)
(TXT) w3m dump (jvns.ca)
| matheusmoreira wrote:
| > programs should print "regular" output to stdout and errors to
| stderr
|
| This is really important. I'd like to expand on this.
|
| Standard output is for the data the program was asked to produce,
| no more and no less. If user asked for some JSON data, standard
| output should contain that exact JSON object and absolutely
| nothing else.
|
| Standard "error" is actually a misnomer. It should have been
| called the standard user stream. Anything meant for the user to
| read on the terminal is supposed to go there. Error messages are
| of course included in that set but so are status messages and
| verbose output.
|
| This ensures the output of programs can be piped into other
| programs seamlessly. Non-output data still gets sent to the
| terminal or redirected somewhere else.
|
| Would have been great if programs were able to easily create new
| terminal-connected file descriptors for specific purposes. They
| could document those numbers in their manuals just like they
| document exit codes. Then users would get "ports" for every
| output. Could cut down on parsing significantly.
|
| For compatibility, they could all redirect to either standard
| output or standard error by default... I think I'm gonna
| experiment with this a bit.
| packetlost wrote:
| I'm not sure I like the "standard user stream" name, but I
| otherewise agree with everything here.
| matheusmoreira wrote:
| Yeah, naming is hard. If there is a better word for "non-
| output", I don't know it.
| packetlost wrote:
| I would maybe call it stdlog or stdinfo vs stderr, but yeah
| naming things is hard.
| matheusmoreira wrote:
| I think stdinfo would exclude error messages from the
| definition, just like stderr excludes info messages.
|
| I really like stdlog. Standard log stream is a pretty
| awesome name. Short and terse, the word "log" doesn't
| even need abbreviation and it's correct since it's a
| superset of error and info streams and also generic
| enough to cover other unforeseen categories.
|
| I'll use it from now on!
| packetlost wrote:
| The idea for info is that it's informational, which is
| always the case regardless of whether it's printing error
| messages due to a failure or informational messages
| because the user specified a `-v` flag or whatever.
| Whether the command failed or not is communicated via the
| exit code. That being said, I do prefer stdlog for the
| reasons: it communicates the intent and usage as
| unambiguously and tersely as possible.
| matheusmoreira wrote:
| > because the user specified a `-v` flag or whatever
|
| The way I see it is the version information and help text
| belong on standard output if the user passes --version
| and --help since that's what the user explicitly asked
| for. When the command is invoked incorrectly, the help
| text should go to standard error while standard output
| should be empty.
|
| I agree about the exit code. People like to parse error
| messages and that's always wrong. Everything should be
| done via exit codes instead.
| packetlost wrote:
| The `-v` was in reference to the common convention of one
| or more `v` flags increasing the verbosity of logging.
| ryandrake wrote:
| C++ has std::clog[1], but it's basically cerr, and the OS
| still only knows about stdin, stdout, and stderr.
|
| 1: https://cplusplus.com/reference/iostream/clog/
| paulddraper wrote:
| I'd name it "standard log."
|
| That's what it is....a log. Of errors, warnings,
| informational messages, whatever to complement the primary
| output.
|
| BONUS: stdlog fits nicely :)
| saghm wrote:
| What about "debug"? I think the important part about stderr
| is that it's "meta" info about how the program is running (or
| ran) rather than what the program is intended to produce as
| output. This seems pretty similar to what often is referred
| to as the "debug" level of logging (which includes lower
| levels of logging like warnings and errors).
| lionkor wrote:
| Unless your app doesn't generate output,then grepping the
| output will not work if it's stderr and it will be confusing
| bombcar wrote:
| You can learn the 2>&1 thing, but it would be nice if there
| was a feature of one of the greps to "slurp up" the error
| output.
|
| Of course, the real problem is there's no standard, the
| standards that do exist are ignored, and each new command-
| line tool generates a new standard.
| sudobash1 wrote:
| It generally isn't possible for grep to "slurp up" the
| error output because stderr does not get passed through
| pipes (by default). This is shell behavior and grep cannot
| do anything about it.
|
| As a side note, some shells have started implementing a
| shorthand for `foo 2>&1 | grep` which is `foo |& grep`.
| ElevenLathe wrote:
| Probably you could do a hack like finding the program at
| the other end of the pipe and looking at its open file
| descriptors, but lots of corner cases to consider.
| matheusmoreira wrote:
| How can you grep output if there's no output?
|
| Can you provide a concrete example of such an application?
| AndrewDucker wrote:
| This is definitely one of the things that PowerShell got right.
| 6 different streams, each of which can be intercepted
| separately and configured differently.
|
| https://learn.microsoft.com/en-us/powershell/module/microsof...
| matheusmoreira wrote:
| There's a lot of good ideas in power shell. I like how they
| broke up the log stream into separate streams by severity. It
| still seems arbitrary and insufficiently general though. Why
| severity and not some other criteria?
|
| What if programs could define any number of output streams?
| By default they could all coalesce into the terminal but
| other programs could connect to each one separately if they
| needed. Like an audio mixer of sorts: by default you get the
| mixed audio but there are ways to access each individual
| voice if needed.
| immibis wrote:
| I don't think that 6 different streams that will always go to
| the same place but some of them are usually turned off are
| very useful. Standard-error/user is useful because it goes to
| a different place. Levels would be better suited to a simple
| global variable, or a level associated with each printed
| line. The chance that someone redirects errors to error.log
| is reasonable, but the chance that someone redirects errors
| to error.log _and_ warnings to warning.log _and_ debug to
| debug.log _and_ verbose to verbose.log is pretty low.
| bobbiechen wrote:
| Nice writeup. Since she mentioned how hard it is to learn these
| conventions, I'll plug my preferred reference when thinking about
| CLIs specifically (rather than TUIs and REPLs) - the Command Line
| Interface Guidelines https://clig.dev
|
| It does include the blog post's rules on exiting on Ctrl-C,
| accepting `-` for stdin, disabling color in pipes, and much more.
| thiisguy wrote:
| This is referenced at the very beginning, just after the table
| of contents.
| bobbiechen wrote:
| Oops, I missed it when I was reading, and assumed it wasn't
| referenced. Thanks!
| mcint wrote:
| I would also recommend, call to attention, the Further Reading
| from CLIG, https://clig.dev/#further-reading. POSIX, GNU, Unix
| resources, Heroku CLI guide, and 12-factor _CLI_ app guide.
| felixhummel wrote:
| I'd add "long-running processes should reload their configuration
| on SIGHUP". :)
| rocqua wrote:
| This isn't a list of shoulds. It's a list of, generally dones.
| Big difference.
|
| This one is still nowhere near universal enough to count in the
| original lisr sadly.
| anthk wrote:
| Don't hardcode readline keybindings.
| Sesse__ wrote:
| "rule 5.1: Ctrl-W should delete the last word [...] I can't think
| of any exceptions to this other than text editors but if there
| are I'd love to hear about them!"
|
| mysql(1) only links to editline instead of readline, where Ctrl-W
| by default deletes everything to the start of the line, not just
| the last word. It drove me mad in the period where I had to use
| it; you just see your entire nice query disappear. :-)
| saghm wrote:
| It could be worse! Back in college, I had the misfortune to
| decide to try to use sqlplus, Oracle's CLI to try to connect to
| their database. Not only did terminal shortcuts like Ctrl-W not
| work at all, but you couldn't even move the cursor earlier in
| the line, and there was no history navigation to get to the
| previous command, so any typo forced you to retype the entire
| thing from scratch. Entering a single forward slash would allow
| you to run the last command verbatim, but that didn't help with
| typos. Ctrl-L also didn't work for clearing the screen, but you
| could manually run `clear scr` to do it instead, because I
| guess having the command just be `clear` wouldn't be obvious
| enough.
| cafard wrote:
| SQL*Plus is pretty basic, but L will show you the previous
| command, a number will give you that line of the previous
| command, to edit, etc.
| Sesse__ wrote:
| If you ever need to do so again, try gqlplus, which wraps
| sqlplus to add such quality-of-life features :-)
| kps wrote:
| It could be worse! You could be using an un-configurable
| modern browser or some such thing where attempting to erase a
| word closes your tab.
| CorrectHorseBat wrote:
| ctrl-w and ctrl-u are just the emacs edit commands from readline.
| If you are a sensible person and use vi mode they do nothing.
| blueflow wrote:
| Do an "stty -a" in the terminal - you will see these two keys
| are handled by the kernel itself and will also work with
| programs reading dumbly from stdin, like "cat".
| kps wrote:
| Ctrl-W originates (on Un*x) from the 'new' BSD tty driver in
| the late '70s. Ctrl-U vs Ctrl-X was one of those BSD-vs-AT&T
| things (where V7 defaulted to '@' 'cause your terminal might
| not have those fancy control characters). `vi` respected the
| current tty settings.
| sysread wrote:
| Non-interactive programs that emit informational output should
| _only_ do so to stderr or a log file so that they may be used in
| a pipe line.
| model-15-DAV wrote:
| As an addendum to Rule 7, `cd -` takes you to the last opened
| directory. Or is `cd` considered part of the terminal emulator's
| job, as a built-in?
| saghm wrote:
| I don't think it's part of the terminal emulator (e.g. xterm,
| gnome-terminal) but the shell (bash, zsh, etc.). You're correct
| that it's not something that's implemented as an external
| program though; the "current directory" is state for a
| currently running terminal session, so changing that state is
| done via the shell interface (either directly by built-in
| commands like cd or indirectly via external commands that use
| those transitively).
| machinestops wrote:
| Note: Child processes can't change the working directory of
| the parent. An external command (that is, not a shell
| builtin, shell function, or externally loaded module) cannot
| change the working directory, because they're launched as
| child processes.
| lyxell wrote:
| I'd like to add: Programs should not add files to your home
| directory and should respect XDG_CONFIG_HOME and friends.
| chriswarbo wrote:
| Ctrl-D for REPLs always bites me with GHCi. My usual approach to
| quitting GHCi is:
|
| - Press Ctrl-D, like normal
|
| - Get confused when nothing happens
|
| - Remember that it doesn't work in GHCi, so run `:q` instead
|
| - Get an error message about "lexical error at character '\EOT'",
| due to Ctrl-D inserting an invisible char at the start of the
| input
|
| - Try `:q` again, without any invisible prefix
|
| - GHCi successfully quits
| jeffrallen wrote:
| You think that's hard, try getting out of vi when you're on a
| keyboard from an unfamiliar country.
| jeffrallen wrote:
| If you are a young sysadmin, take the time to.learn Emacs. Not
| because Emacs is good (but it is) but because deadline keys are
| Emacs keys, so once you know Emacs you know shell, MySQL, etc.
|
| Play your terminal like a piano . Your livelihood depends on it.
| neilv wrote:
| Additional suggestions:
|
| * Respect the user's default foreground and background color.
| Don't change them without good reason.
|
| * If you use colors, make them legible regardless of what the
| default background and foreground colors are, and regardless of
| the terminal's color map.
|
| * Don't use color as the only indication of something. The user's
| terminal might not display it, and it probably won't be preserver
| in copy&paste into notes.
|
| * Use emoji only judiciously, if at all. Similar with gratuitous
| non-ASCII characters. It doesn't display everywhere, it doesn't
| paste well everywhere, and emoji can be a bit much when
| copy&pasted into some notes.
|
| * In a scrolling (non-full-screen) stdout-ish output, don't
| delete important information that you showed temporarily. For
| example, hiding warnings or filenames compiled, to display a
| green checkmark for done For another example, clearing the screen
| of Web app build information (including package security
| warnings!) to display a message that it's running in dev mode.
| People might want to see that information, or copy&paste it into
| notes.
|
| * If you went full angry fruit salad with your command line
| program, because it's your baby, and you're having fun hamming it
| up, that's fine, but please provide an easy preference setting
| for people to opt out of that. Your program is probably only one
| of many things on user's workstation display, where other
| programs might be using color and visuals more meaningfully, so
| animated throbbing red explosions for the code reformatter is a
| bit much.
| ucarion wrote:
| What does "cooked" mode mean in the context of this article?
| kelnos wrote:
| [delayed]
___________________________________________________________________
(page generated 2024-12-12 23:00 UTC)