Here's another one:<p><i>Provide explicit flags for default behavior</i>.<p>For example, if your lines-of-code counting utility excludes preprocessor directives by default, and includes them when you pass "-i", provide an "-x" switch that signals to use the default behavior. This way, when someone wants to write a bash script that uses your utility, they can do this:<p><pre><code> case $include_directives in
y)
LOC_FLAGS='-i';;
n)
LOC_FLAGS='-x';;
esac
myloc $LOC_FLAGS
</code></pre>
This has three benefits:<p>1.) It's explicit, and thus more obvious and clearer.<p>2.) It's more consistent, so there's no risk of empty/unset variables, whitespace, or other edge conditions screwing up a delicate munging operation.<p>3.) It's change-tolerant, so if future versions of your utility change the default behavior, scripts will continue functioning as expected.
Oh, and another:<p><i>Use your language's command-line option processing libraries.</i><p>OptionParser in ruby and argparse in python. There is no reason to eschew these libraries: they're part of the standard library, they require zero coupling to your app logic, and they handle all of the edge cases for free.<p>"But I can just shift the arguments", you say! Yeah? Great! What if the user pipes input through STDOUT? What if the user passes a flag, a required argument, and then another flag? Will your script read the last flag correctly, or has the naive logic already entered "required argument processing mode"? Just use the library. It's a solved problem!
This might not be shared by others, but here it goes.<p>If your CLI program is a file-format conversion utility, please include a way to dump meta-data, header formats, etc. Don't just silently convert from A to B, allow me to get at the info you have gathered from the input.<p>For example, a binary disassembler SHOULD dump the executable header format. An spreadsheet converter utility SHOULD display how many sheets there are, if there are macros, how many rows, etc.<p>One of my pet peeves is pdftotext, a very nifty utility that I use to convert PDF reports to ASCII for subsequent awking. pdftotext has an option to specify start and end pages to extract, but it doesn't have an -i or --info option that tells me how many pages a PDF file has. So, my scripts have a very high upper-limit, like 1000, and it converts the file page by page, until the output text page has a size of zero.<p>Which reminds me, I should probably fork the fucker this weekend, now that I have some free time.
One thing that always infuriates me:<p>If I go to --help or the man page for your command, and don't see a real example of how to use it immediately, you've failed me as a user.<p>Seeing your syntax tree and a list of every option and its description doesn't help me when I'm first trying to use your program. I just want to see one or two quick examples of real commands with a short sentence explaining each. After that I'll dive into the mess that is the dozens of flags and inputs to decipher exactly what I want.
<p><pre><code> Do you really want to do this (y/n)?
</code></pre>
i would rather see this as<p><pre><code> Do you really want to do this (y/N)?
</code></pre>
capitalize the option that will be used by default if you hit enter with no other input.
One more:<p><i>Keep your "usage" blurb succinct and clear.</i><p>Don't clobber your users' terminals with two pages of output when they're not expecting it. If "yourapp", "yourapp -h" or "yourapp --invalid-flag" results in two screenfuls of information containing your app's license, installation instructions, contribution notes, an exhaustive listing of every single one of the 100 available subcommands, and a verbose representation of a configuration setting that 75% of your users won't care about, you're doing it wrong. (I'm looking at you, rvm).<p>This is similar to the idea of "You don't really understand something unless you can explain it so your grandmother gets it." Your app doesn't really have a sensible interface unless the <i>top layer</i> of its abstraction, or the <i>most common</i> commands, can be summarized in less than scrillions of lines of text. If you simply can't trim it down far enough, it's because <i>you're breaking from the Unix philosophy and your utility is doing too much</i>.
<i>The name should be short. A long name will be tedious to type, so don’t call you version control program my-awesome-version-control-program. Call it something short, such as avc (Awesome Version Control).</i><p><pre><code> $ my-aw<TAB> # yay!
</code></pre>
Personally, I am not a big fan of everyone using two or three-letter linux names for everything. We have a lot of options now for autocompletion and seeing what is available, so long names are no longer a talking point.
"GUIs also have the advantage when it comes to presenting and editing information that is by nature graphical. This includes photo manipulation and watching movies (I have always wanted a program that shows a movie in my terminal by converting it to ASCII art in real-time, that would be sweet)."<p>This is an interesting discussion - what is the CLI, exactly? My personal PDF viewer is Zathura[1], which is controlled like VIM. On the other hand, programs like Kismet run on a terminal, but have mouse controlled menus.<p>Personally, I feel that Zathura is a CLI application, even though it depends on X, because the interaction is done in a keyboard driven way with no graphical widgets.<p>[1]: <a href="http://pwmt.org/projects/zathura/" rel="nofollow">http://pwmt.org/projects/zathura/</a>
(edit) There is a bit of terminology substitution going on in linked article. Command line interface is a shell. That's where one types the commands. Calling command options and arguments an interface may be technically correct, but it is not what is conventionally understood under a term of <i>CLI</i>.<p>---<p>Speaking from an experience writing CLIs for configuration-heavy embedded devices, the key design element of a functional CLI is a <i>context-aware TAB expansion</i>. This is what makes a CLI truly convenient for routine use.<p>For example, if a mysql shell was smarter, it would've been allowing this:<p><pre><code> > use p<tab><enter> expands to "use production"
> show c<tab> s<tab><tab><enter> expands to "show columns from secondary"
> select * f<tab> s<tab><tab> ... expands to "select * from secondary ..."
</code></pre>
It would also be nice to make OS shell more aware of individual commands' options, and to allow for example:<p><pre><code> # ip addr <tab> shows "ip addr add"
# <tab> shows "ip addr del"
# <tab> shows "ip addr"
</code></pre>
This is possible through hardcoding these expansions into the shell, but that's not very elegant, is it? On the other hand allowing to integrate arbitrary commands with the shell in a <i>generic</i> way would require putting together some sort of interface/manifest contraption and it would most likely go against the very spirit of Unix simplicity. So catch 22 it is.
ESR's "The Art of Unix Programming" has a good section on consistent default of command line options<p><a href="http://www.catb.org/esr/writings/taoup/html/ch10s05.html" rel="nofollow">http://www.catb.org/esr/writings/taoup/html/ch10s05.html</a>
You might want to fix this typo.<p>> Maybe it¿s just me, but I prefer to remotely control computers via SSH over VNC<p>If you're really running "SSH over VNC" then you're doing it wrong. ;)<p>> I have always wanted a program that shows a movie in my terminal by converting it to ASCII art in real-time, that would be sweet<p>man mplayer and look for the -vo flag which controls the video output
mode/driver. Two common options for video output (-vo) are the 'aa'
(ASCII Art) and 'caca' (Color Coded ASCII Art). There is a third, 'bl'
("blinkenlights") but it's hardware dependent.
I agree with most of the article, except the yes/no part. In fact I think it's better to do :<p>"Do you want to do this (Y/n)?"<p>Where the most common option is uppercase so I can just hit enter.
I'm glad he mentioned the "Silence trumps noise" point.
I like to call the idiom "no news is good news".
Tell me only when I need to know something (like a failure); "-v" is always there if I need it.
It feels uncomfortable to get no output at first, but once you get used to it there's much less to read.<p>It's rather like the Plan 9 convention of programs returning strings instead of ints when then terminate; an empty string means success, a non-empty string contains the error message. I wish other OSes had adopted that.
Additionally, for interactive CLI programs or suites of programs, consistency is key. Offer the same way to select options, confirm or deny information, input data etc.<p>I'm also working on a project where by entering "?" at any interactive section you're taken to an interactive help menu. From here you can query (amongst other things) the state of the program, something that isn't always clear when you're using command line software, as you can't have extra info somewhere in the corner or whatever.
One cool feature of the juniper junos CLI is that all the CLI commands have an option for XML output, making parsing of the CLI output in scripts a little more sane.
<i>Non-interactive programs get the most attention in this article, while text-based user interfaces are barely covered at all.</i><p>That's disappointing, I was hoping I'd learn how vi, etc. worked from this, since I know nothing about writing command line interfaces other than input and output to the last column of the last line of the terminal. Does anyone know of a good article/introduction to this?
> Silence trumps noise<p>How about, ec2-server-start -n 4 -t medium -i img-xxxg
Which expands to start 4 medium instances using image img-xxxg. Will you prefer a long wait and then silently back on prompt or an indication of something happening?<p>I agree with what he is saying, but I think there is a hint of unfair generalization here.<p>> Naming your utility<p>Again small unix commands are like precious three letter domain names. Not always viable. Also, although most of single letter commands are free, one should avoid to name a CLI binary in single letter, because 1. users often type single letter stuff by mistake. 2. users use single letter aliases.
The article is interesting up to a point, but what really struck me is that this blog claims to be written by a 15 year old. I think the topics and depth of the other articles on the blog spell great things for this guy's future!
> Multi-letter options start with two hyphens, and each such argument must be separated with spaces.<p>That's something that's always annoyed me about screen; commands such as "wipe" are "screen -wipe"
See the paper by Rob Pike and Brian Kernighan 'Program Design in the UNIX Environment' (aka 'cat -v considered harmful'):<p><a href="http://harmful.cat-v.org/cat-v/" rel="nofollow">http://harmful.cat-v.org/cat-v/</a>