[HN Gopher] CLI Guidelines - A guide to help you write better co...
       ___________________________________________________________________
        
       CLI Guidelines - A guide to help you write better command-line
       programs
        
       Author : bfirsh
       Score  : 145 points
       Date   : 2020-12-04 16:33 UTC (6 hours ago)
        
 (HTM) web link (clig.dev)
 (TXT) w3m dump (clig.dev)
        
       | macintux wrote:
       | Thanks, this is sorely needed. Looking forward to taking time to
       | dig more deeply into it.
        
       | postgrescompare wrote:
       | Thank you! I'm working on the cli for
       | https://www.postgrescompare.com and I really want to make it
       | great!
        
       | klodolph wrote:
       | I think we should abolish different prefixes for short/long flags
       | except for core POSIX programs (like ls, cp, rm, mkdir, etc.) In
       | other words, "-flag" should be interchangeable with "-flag". The
       | ONLY reason I can think of why you would not recognize "-flag" as
       | equal to "--flag" is because you want to recognize it as "-f -l
       | -a -g", which makes sense for programs like ls, but for 99% of
       | newer programs, don't do it. Just make "-flag" and "--flag"
       | equivalent.
        
         | attractivechaos wrote:
         | > _for 99% of newer programs, don't do it_
         | 
         | The majority of recent tools in my circle follow this Unix
         | convention. That is a natural result when you use
         | getopt_long().
        
       | mdoms wrote:
       | There's some excellent content here. Unfortunately it is hidden
       | behind an excessively wordy document. You should consider
       | bringing in a ruthless editor to cut this down to about a quarter
       | of it's current length.
        
       | dllthomas wrote:
       | Loving this!
       | 
       | As a nit:
       | 
       | > Let the user escape. Make it clear how to get out. (Don't do
       | what vim does.) If your program hangs on network I/O etc, always
       | make Ctrl-C still work. If it's a wrapper around program
       | execution where Ctrl-C can't quit (SSH, tmux, telnet, etc), make
       | it clear how to do that. For example, SSH allows escape sequences
       | with the ~ escape character.
       | 
       | I find it confusing that vim is considered less discoverable here
       | than SSH. In either case, you can find the information in the
       | manual (not ideal, but a baseline). In the case of vim, when you
       | hit ctrl-c it tells you how to leave for real. So far as I'm
       | aware, there's no real way to discover the magic ~ invocations in
       | SSH except resorting to the manual or exhaustively trying every
       | key combo with no evidence that you're on the right track or that
       | there's even a track to be on.
       | 
       | Also, vim _is_ (in part) a wrapper around program execution.
        
         | kevincox wrote:
         | I agree, if you press Ctrl-C vim (with default settings)
         | literally tells you how to quit. `\n~` in SSH is completely
         | unrecoverable.
        
       | kitotik wrote:
       | This is a great resource, thanks for the effort.
       | 
       | I strongly disagree with the " Don't bother with man pages"
       | advice. It's extremely annoying when tools don't provide a
       | manpage. The overhead of opening up a browser to reference
       | command is cumbersome and highly annoying.
       | 
       | There are tools such as pandoc that make generating manpages from
       | various source formats very easy.
       | 
       | Perhaps it is just my grouchy old man syndrome...
        
         | jen20 wrote:
         | Absolutely - I can't buy into the "don't write man pages" idea.
         | 
         | For many years I've had this function in my RC files for macOS:
         | pman() { man -t "$@" | open -f -a Preview; }
         | 
         | It opens the given man page in Preview, typeset beautifully. No
         | such thing is available for random text printed to the console,
         | nor is a console pager (as recommended by this article) an
         | acceptable substitute for this.
        
         | mmalone wrote:
         | They're not saying you shouldn't provide command-line help.
         | Just that you should deliver them through a `help` subcommand
         | and/or through a `--help` flag (like `git` does) because people
         | don't find man pages and because man pages don't work on every
         | platform.
        
           | reaperducer wrote:
           | Why not both?
           | 
           | Write the help for the more verbose of the two, then trim it
           | back for the other.
           | 
           | Everyone gets what they want.
        
           | kitotik wrote:
           | Right. I still prefer terse help text from the command line,
           | and more in-depth in the man pages.
           | 
           | I find commands with copious -h output and having to pipe
           | that into a pager or using scroll back a far worse UX than
           | just opening up a man page that's easily searchable /
           | scrollable.
        
             | mmalone wrote:
             | Yea that's reasonable, but there are pros and cons and it's
             | also definitely an opinion :).
             | 
             | I don't see the problem with piping help text through a
             | pager (that's literally all `man` is doing). Alternatively,
             | a tool can use a pager automatically (as `git help ...`
             | does). So `man` isn't required to have a pager. Whether you
             | should use a pager by default is a different argument.
             | 
             | That said, I find pagers annoying because it's hard to
             | switch back and forth between typing a command and the
             | docs. That's way easier to do with scrollback. Although
             | someone in this comment thread also mentioned the `PAGER`
             | env var, and that you can set `PAGER=cat`, which is a good
             | pro-tip. So, TIL.
             | 
             | Still, if you're concerned with command-line ergonomics for
             | a broad audience I think there are more people that either
             | 1) know how to `| less` or 2) prefer or don't care about a
             | pager than people who are gonna automatically just know
             | they can do `PAGER=cat man <some-subcommand-of-my-cli-
             | tool>`.
             | 
             | Plus, there's still the cross-platform argument.
             | 
             | Oh, and OP doesn't mention this, but man pages also
             | complicate install, uninstall, versioning, and having
             | multiple versions of a tool installed simultaneously.
             | Built-in help is obviously just works and is distributed
             | with the standalone binary. To use man pages you have to
             | place additional artifacts on the system and make sure
             | they're managed correctly (e.g., versioned). It's
             | additional complexity with basically zero benefit.
             | 
             | So yea. Seems like, as a rule, their guidance is
             | reasonable. I don't see a lot of benefit to using man pages
             | other than "because that's how it's always been done".
        
               | scbrg wrote:
               | > I don't see a lot of benefit to using man pages other
               | than "because that's how it's always been done".
               | 
               | Man pages are organized, categorized, indexed and
               | searchable. It's a common format that can be read by
               | multiple pagers (including dedicated GUI browsers for
               | those so inclined). They're also available when the
               | command might not be. There are definitely benefits over
               | _command --help_ other than the syntax of the invocation.
               | 
               | > I find pagers annoying because it's hard to switch back
               | and forth between typing a command and the docs.
               | 
               | less -X
               | 
               | If people don't know about _man_ , why not teach them? A
               | simple line in the summary -h gives that says: _For more
               | information, read the man page: man foo_.
               | 
               | > Plus, there's still the cross-platform argument.
               | 
               | This just makes me sad. I don't know exactly where we'd
               | be if every computer system didn't feel it needed to be
               | garbage just because Windows is. But I don't think it'd
               | be quite as bad as where we are.
        
           | colordrops wrote:
           | Perhaps prioritize a --help flag over a man page, but add
           | both if time permits. In any case, a man page is static text
           | and much easier to implement than --help, especially if you
           | have multiple help modes (e.g. verbose or different sets of
           | commands).
        
           | dllthomas wrote:
           | Man pages improve discoverability. You only find --help
           | contents if you already know which command you want. Man
           | pages are searchable (with `man -k` or `apropos`).
           | 
           | This is most relevant when it's a tool that isn't going to be
           | immediately obvious anyway (if I'm trying to figure out how
           | to do XYZ on heroku, it's not unreasonable to expect me to
           | look at the heroku program I installed), and especially when
           | it's a tool that might be installed by default or installed
           | and forgotten about.
        
             | jcynix wrote:
             | Agreed. And man page content is searchable too, even with
             | regular expressions while in a pager like less.
        
               | dllthomas wrote:
               | Sure, but they advise pulling up a pager anyway if the
               | content is long.
        
         | _underfl0w_ wrote:
         | Maybe I'm suffering from similar syndrome, but I'm under 30 in
         | human Earth years. However, I very much agree with you and
         | would take it a step further to say that programmatically
         | opening the browser with the help flag is also very unwelcome
         | (I'm looking at you, git >.> )
        
           | rhencke wrote:
           | It is your choice, in Git:                   git config
           | --global help.format man
        
             | kitotik wrote:
             | TIL! Thanks for that.
        
       | dllthomas wrote:
       | > Which means O_O and OwO are the only emoticons that are also
       | valid environment variable names.
       | 
       | O_o
        
         | jdporter wrote:
         | XD
        
         | fwip wrote:
         | uwu what's this?
        
       | EE84M3i wrote:
       | It's kind of crazy that we still don't have a standard computer
       | readable way for a program to describe it's argument structure in
       | a computer readable way that could be used for command line
       | autocomplete. E.g. something like an extra section in the binary
       | that describes how arguments are processed.
        
         | d0mine wrote:
         | http://docopt.org/
        
         | mmalone wrote:
         | Yea, like, imagine if posix pipes and command-line flags could
         | be typed.
        
           | vageli wrote:
           | Powershell offers this I believe.
        
             | jmmv wrote:
             | That's right. I recently wrote on this topic:
             | https://jmmv.dev/2020/10/powershell-cmdlet-params.html
        
             | mmalone wrote:
             | Yep. Not perfect... type systems have come a long way since
             | PowerShell did it. But it's a good start.
             | 
             | Look at stuff like PowerShell secure strings for an example
             | of the sort of neat stuff you can do.
        
             | ChrisSD wrote:
             | NuShell is also attempting this. Both are cross platform.
             | 
             | https://github.com/nushell/nushell
        
               | _underfl0w_ wrote:
               | Thanks for mentioning this! It looks super interesting,
               | but I hadn't heard of it before.
        
           | delusional wrote:
           | The general problem is that typing for these sorts of systems
           | suck. If it works it's a nice little safety feature, but when
           | the types don't line up it's infuriating. Treating everything
           | as a lowest common denominator makes compatibility trivial.
        
       | jmmv wrote:
       | Hah. This is a topic that's dear to my heart and have blogged
       | occasionally about it... but never in such a comprehensive form.
       | Great job! Now... I gotta read through everything.
       | 
       | But... here is a series of blog posts in which I covered similar
       | themes years ago: https://jmmv.dev/series.html#CLI%20design
       | 
       | And here is another single post that touches upon a single
       | guideline I came across while skimming through the text:
       | https://jmmv.dev/2020/08/config-files-vs-directories.html . It
       | might be helpful in providing more details about the _whys_
       | behind each guideline.
       | 
       | Lastly, I'll also mention the "Producing open source software"
       | book by Karl Fogel, which provides a lot of useful advice too,
       | especially on how to ship the tools: https://producingoss.com/
        
       | bfirsh wrote:
       | Hello HN!
       | 
       | We're Ben, Aanand, Carl, Eva, and Mark, and we made the Command
       | Line Interface Guidelines.
       | 
       | Earlier this year, I was working on the Replicate CLI [0]. I had
       | previously worked on Docker so I had a bunch of accumulated
       | knowledge about what makes a good CLI, but I wanted to make
       | Replicate _really_ good, so I looked for some design guides or
       | best practices. Turns out, nothing substantial had been published
       | since the 1980s.
       | 
       | On this search I found a superb blog post by Carl about CLI
       | naming [1]. He must be the only person in the world who cares
       | about CLI design and is actually a good writer, so we teamed up.
       | We also were joined by Aanand, who did loads of work on the
       | Docker CLIs; Eva, who is a technical writer, to turn our scrappy
       | ideas into a real piece of writing; and Mark, who typeset it and
       | made a super design.
       | 
       | We love the CLI, but so much of it is a mess and hard to use.
       | This is our attempt to make the CLI a better place. If you're
       | making a tool, we hope this is useful for you, and would love to
       | hear your feedback.
       | 
       | Some of it is a bit opinionated, so feel free to challenge our
       | ideas here or on GitHub! [2] We've also got a Discord server if
       | you want to talk CLI design. [3]
       | 
       | [0] https://replicate.ai/
       | 
       | [1] https://smallstep.com/blog/the-poetics-of-cli-command-names/
       | 
       | [2] https://github.com/cli-guidelines/cli-guidelines
       | 
       | [3] https://discord.gg/EbAW5rUCkE
        
         | jdporter wrote:
         | _Hit us up on Twitter._
         | 
         | Eh, I think not.
         | 
         | The "commands" I create are, most often, small tools for my own
         | use, so I don't worry about making the names short. I always
         | try to make the name a verb, or include a verb, e.g.
         | "fetchbookmarks", "deleteduplicates"; one exception would be in
         | the case of converters, in which case "convert" is implicit,
         | e.g. "csv2xml" or whatever; and there may be other cases where
         | the verb is implied. The Huffman Coding is important, though,
         | and I have made some tools I use _a_ _lot_ , so I gave them
         | short names. I use gvim a lot, and the wrapper I wrote for it
         | (which does smart finding - it will load foo.cpp wherever it is
         | under your cwd, as long as there's only one) I named _g_. I don
         | 't expect to distribute this tool, so I don't care. :-)
        
         | abathur wrote:
         | Thanks for writing! I haven't had a chance to read it yet, but
         | I'm always looking for new opinions here. Looking forward to
         | going through it :)
        
         | ucarion wrote:
         | Since you bring up Docker, this little behavior has always
         | baffled me:                   $ docker image ls -h         Flag
         | shorthand -h has been deprecated, please use --help
         | 
         | But:                   $ docker image -h ls         Flag
         | shorthand -h has been deprecated, please use --help
         | Flag shorthand -h has been deprecated, please use --help
         | Flag shorthand -h has been deprecated, please use --help
         | 
         | What's up with that? I'm guessing cobra nonsense, because
         | everyone ends up wrapping cobra's weird API differently...
        
           | codetrotter wrote:
           | Looks like it wants you to type --help, not -h.
           | 
           | Still weird though, since -h is indeed a very very common
           | shorthand used in many commands.
        
           | whelming_wave wrote:
           | I know you're talking about how it's repeated three times,
           | but something else here really bothers me.
           | 
           | I understand if they're deprecating it because they plan to
           | replace it with something else, but if they don't then I'll
           | be pretty disappointed. From their docs, it looks like some
           | of their other subcommands have shorthands which conflict
           | with `-h'? Fine, I guess, but that just means when `-h' does
           | work it'll shoot people in the foot with that other behavior.
           | 
           | Software that clearly knows what I want, but refuses to,
           | annoys me so much. For example,                   $ python3
           | Python 3.9.0 (default, Dec  2 2020, 10:34:08)          [Clang
           | 12.0.0 (clang-1200.0.32.27)] on darwin         Type "help",
           | "copyright", "credits" or "license" for more information.
           | >>> quit         Use quit() or Ctrl-D (i.e. EOF) to exit
           | 
           | because they added `quit' as a top level variable with a
           | `__str__' defined which returns that string. Do anything
           | else! Make the `__str__' definition quit the program or
           | something, test if it's being run at the top level in the CLI
           | and quit, special case the CLI input so if only `quit' is
           | entered, it quits. Heck, maybe just prefill the `quit()' on
           | the next line so I just have to hit return. Do anything but
           | instruct me to do what you should have done in the first
           | place.
        
             | resonantjacket5 wrote:
             | I mean if you did that how would you access 'quit' if it is
             | defined? It's a bit more complicated than it seems.
             | 
             | Though I get your general point.
        
               | cle wrote:
               | You just access it, it's just a normal variable.
               | $ python3         Python 3.8.6 (default, Nov 18 2020,
               | 23:56:33)         [GCC 9.3.0] on linux         Type
               | "help", "copyright", "credits" or "license" for more
               | information.         >>> quit         Use quit() or
               | Ctrl-D (i.e. EOF) to exit         >>> q = quit
               | >>> quit = "foo"         >>> quit         'foo'
               | >>> quit()         Traceback (most recent call last):
               | File "<stdin>", line 1, in <module>         TypeError:
               | 'str' object is not callable         >>> q()         $
        
         | uhoh-itsmaciek wrote:
         | This is great, thank you! Under pagers, maybe add a note to
         | respect PAGER if set? I prefer relying on terminal scrollback
         | in some situations, and e.g. in psql often set PAGER=cat. Git
         | respects this, too.
        
         | raywu wrote:
         | Thanks for these resources! Definitely relate. CLI is the
         | original chatbot
        
         | swyx wrote:
         | you're not the only ones who care! I've been collecting CLI
         | design thoughts and nodejs utilities for a couple years:
         | https://github.com/sw-yx/cli-cheatsheet/blob/master/README.m...
         | just added yours!
        
       | alcover wrote:
       | Nice initiative!
       | 
       | A few remarks :
       | 
       | - the intro text is way too long
       | 
       | - you contradict yourselves about stdout :                 `Log
       | messages, errors, and so on should all be sent to stderr.`
       | `Don't treat stderr like a log file, at least not by default.`
        
       | zokier wrote:
       | > The command line of the past was machine-first
       | 
       | > Traditionally, UNIX commands were written under the assumption
       | they were going to be used primarily by other programs
       | 
       | Is there any real factual basis for these claims? I find them
       | hard to believe, considering the origins of UNIX and the fact
       | that shell was the primary (or even only) user interface for the
       | system, and it was pretty much from day 1 designed as an
       | interactive system (contrasted to the more batch/system oriented
       | mainframes of IBM etc)
        
         | nrclark wrote:
         | I'd say say there's some truth to it, but maybe in an
         | accidental way.
         | 
         | Shell scripts have been part of UNIX since day 1. A lot of
         | early UNIX commands were implemented as scripts, and shell was
         | always intended to be one of the main extension mechanisms for
         | users. Scripting is fundamentally based on the assumption that
         | a script will run various commands, glued together in a user-
         | specified way.
         | 
         | So it's true to say that most early UNIX commands were designed
         | to be useful in a script, which implies that they were designed
         | for use by programs. Maybe not designed _exclusively_ for use
         | by programs, but definitely an important design consideration.
        
         | reaperducer wrote:
         | My recollection is that non-programmers followed the
         | instructions in the binder, which told them how to log in, and
         | then how to start the program they needed. Very basic stuff.
         | Actual commands were the province of programmers.
        
       | gruez wrote:
       | Why are the font sizes so huge? The computed font size is 30px,
       | compared to 12px for hn.
        
       ___________________________________________________________________
       (page generated 2020-12-04 23:00 UTC)