[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)