Making the best CLI programs - Programming On Unix

Users browsing this thread: 1 Guest(s)
z3bra
Grey Hair Nixers
BEWARE: big post ahead.

TL;DR: act as a filter, easy to parse > easy to read

Command line interfaces (for now) only have to ways for interfacing with the user: stdin and stdout. Both are immutable, as in, what's written to it can't be erased.
To me, a good CLI program should act as a data filter. Taking a continuous stream of data on it's input, and output the same data, "filtered". All kinds of metadata and "behavior tweaking" methods (such as flag) should be given as an argument to modify the default behavior of the tool.

When you write a tool, you are supposedly aware of what the filter should be, so the hardest part is to figure out what the data should be. Here are a few hints I've gathered,
either by taking advices from other people or failing miserably (sometimes both!):

input:
0. Do not mess "data" and "metadata"

Let's take "grep" as an example. Its default behavior is to "filter out" all lines where a PATTERN doesn't appear within a data STREAM.
Here are a few "misimplementations" of how "grep" could have been written:
Code:
$ echo PATTERN | grep FILE0 FILE1
$ echo FILE0 FILE1 | grep PATTERN
$ printf "%s\n%s\n" "PATTERN" "FILE0" | grep

The last one is over-exagerated, but the first two could have been valid implementations. They both suffer the same issue though: they don't make the tool act like a filter (or to reformulate it: they can't operate on STREAMs).

1. Limit the number of flags

I often hear people complaining about one-letter flags limiting you to ONLY 26 flags. But I personally think that 26 flags is already too much!
If your tool can handle this much behavior changes, it is likely too complex, and certainly should be splitted in multiple different tools.
Take "ls" as an example. POSIX specifies 23 flags for it. GNU ls has 40 flags! (not even counting --long-opt only flags):
Code:
$ ls --help | grep -o "\s-[a-zA-Z0-9]" | sort | uniq | wc -l                  
40

That is way too much. For example, the flag -r could be dropped:
Code:
$ ls -1 -r
$ ls -1 | tac

The flags -g and -o don't make much sense either, as they filter the output internally (removing either the OWNER or GROUP column).

These flags were indeed added to help the user, but IMO they get in the way as they make the tool more complex to use (more docs and more code can't be a way to go for "simpler" tools)

2. Assume data will be messed up

As much as possible, avoid rigid protocols and format for your input data, and try to simplify your input as much as possible.
If you write, for example, and MPD client that would read commands on stdin, prefer simple inputs:
Code:
$ echo "volume 50" | ./pgm
$ ./pgm <<COMMAND
{
    "command": {
        "type":  "set",
        "key":   "volume",
        "value": "50"
    }
}
COMMAND
One might argue that JSON is easy to parse, well defined and such. That doesn't make it a nice input format, really.

output:

0. Prefer "parseable" to "readable"

Make your output easy to parse, rather than easy to read. Most unix tools work with lines, and play with separators (the famous $IFS variable). Try to format your output as such (tabulations make a great separator!).
Prefer good documentation to verbosity.
Consider a program that would print out the weather in different city. It could have the two following outputs (reading city names on stdin):

Code:
$ printf '%s\n%s\n' "Mexico" "Oslo" | weather
City: Mexico
Wind speed: 10mph
Humidity: 17%
Raining probability: 2%
Temperature: 35°C

City: Oslo
Wind speed: 22mph
Humidity: 44%
Raining probability: 37%
Temperature: 8°C

$ printf '%s\n%s\n' "Mexico" "Oslo" | weather
Mexico    10    17    2    35
Oslo    22    44    37    8

The second output is pretty "hard" to read from a user POV. Now try to write a quick tool that would display only the city name and raining probability...
As I'm a cool guy, here is the one for the second output:

Code:
$ printf '%s\n%s\n' "Mexico" "Oslo" | weather | cut -f1,4
Mexico 2
Oslo 37

It's easier to format RAW data than strip down a formatted one.

1. Your output is an API

Think well about how you format your output data, because some people will rely on it.
If you take the example above, some people will have a hard time if you suddenly decide to swap the temperature with the humidity value.
Be consistent, document your tools and remain backward compatible as much as possible.

2. Be stupid

Don't try to look cool by checking wether the user is writting to a terminal or not, and change to output accordingly.
This will only confuse the users that will not understand why their parsing tools can't parse what they usually get.

The simpler, the better.


Messages In This Thread
Making the best CLI programs - by venam - 23-05-2016, 02:13 AM
RE: Making the best CLI programs - by jkl - 23-05-2016, 04:49 AM
RE: Making the best CLI programs - by z3bra - 23-05-2016, 10:20 AM
RE: Making the best CLI programs - by jkl - 23-05-2016, 10:51 AM
RE: Making the best CLI programs - by pranomostro - 28-05-2016, 10:50 AM
RE: Making the best CLI programs - by z3bra - 29-05-2016, 10:52 AM
RE: Making the best CLI programs - by josuah - 01-06-2016, 10:40 AM
RE: Making the best CLI programs - by z3bra - 01-06-2016, 01:15 PM
RE: Making the best CLI programs - by z3bra - 02-06-2016, 03:27 AM
RE: Making the best CLI programs - by jaagr - 04-06-2016, 03:10 AM
RE: Making the best CLI programs - by z3bra - 04-06-2016, 05:01 AM
RE: Making the best CLI programs - by venam - 14-09-2016, 01:58 PM
RE: Making the best CLI programs - by jkl - 14-09-2016, 02:03 PM
RE: Making the best CLI programs - by venam - 14-09-2016, 02:05 PM
RE: Making the best CLI programs - by venam - 12-10-2016, 12:52 AM
RE: Making the best CLI programs - by apk - 12-10-2016, 12:34 PM
RE: Making the best CLI programs - by acg - 12-10-2016, 09:57 PM
RE: Making the best CLI programs - by pranomostro - 13-10-2016, 05:18 AM
RE: Making the best CLI programs - by z3bra - 13-10-2016, 08:53 AM
RE: Making the best CLI programs - by pranomostro - 13-10-2016, 02:12 PM
RE: Making the best CLI programs - by josuah - 17-10-2016, 05:16 PM
RE: Making the best CLI programs - by venam - 25-11-2016, 04:07 PM
RE: Making the best CLI programs - by freem - 04-12-2020, 11:27 AM
RE: Making the best CLI programs - by venam - 21-06-2021, 02:32 AM
RE: Making the best CLI programs - by seninha - 21-06-2021, 06:23 AM
RE: Making the best CLI programs - by venam - 21-06-2021, 07:41 AM
RE: Making the best CLI programs - by z3bra - 24-06-2021, 04:59 AM
RE: Making the best CLI programs - by jkl - 12-10-2021, 05:59 AM
RE: Making the best CLI programs - by freem - 15-10-2021, 12:49 PM
RE: Making the best CLI programs - by z3bra - 17-10-2021, 07:54 AM
RE: Making the best CLI programs - by Kohaku - 03-11-2023, 01:18 PM
RE: Making the best CLI programs - by neeasade - 08-11-2023, 02:29 PM
RE: Making the best CLI programs - by jkl - 09-11-2023, 10:54 PM
RE: Making the best CLI programs - by rocx - 28-11-2023, 08:11 PM