Thoughtful CLI design π
A command-line interface (CLI) is one of the oldest, and still one of the most useful, ways to interact with a computer. CLIs provide a text-based interface to the user (whether a human or program) to perform various functions or can provide starting values used to launch a graphical user interface (GUI).
A familiar example of a CLI is the ls command that is ubiquitous across Unix and Linux operating systems, including macOS. Short for "list", its function is to list files and directories on your system.
Anatomy of a CLI π
A basic CLI is a program that takes commands, flags, and arguments, and produces some sort of output in response.
Commands (and sub-commands) often represent a particular action to take. For some CLIs, the only command is the CLI name itself. In other cases, a CLI could have various functions that it can perform, each represented by a sub-command. Sub-commands can have further sub-commands of their own.
Flags, also referred to as switches, are optional operators that can modify the operation of the command they are attached to. Flags can stand alone, in which case they behave as boolean values (either the flag is present or is not), but can also take data in the form of arguments.
Flags in Linux/Unix programs are prefixed with
-(dash, or hyphen) for "short"-style flags, which consist of a single character and which can often be combined together (for example:cp -uavto copy files using the-u,-a, and-vswitches), and--(two consecutive dashes) for "long" commands (--update,--archive, and--verbose, respectively), which are more descriptive but which cannot be combined as short flags are. For example, these are the same:cp -uarv ~/src/myprog /mnt/Archive/src/ cp --update --archive --recursive --verbose ~/src/myprog /mnt/Archive/src/
Clearly, one of these lines is easier to type, while the second is easier to understand. This is often the trade-off between these flag styles.
On Microsoft Windows, flags are typically prefixed with
/and are rarely combined together as they are on Linux/Unix systems.Arguments are data provided by the user to satisfy the needs of either a command or flag. Arguments can be either required---something needed by the command or flag to function at all---or optional, in the case where there is either a default value that's used in the absence of an argument, or where the value can be auto-generated by the program unless the user wants to use a value of their own choosing.
Output can be in text form as output to the user (printing to stdout), but may also produce a file or perform other tasks.
Commands and subcommands π
Commands and subcommands represent a particular action, or heirarchy of actions, to take.
A good example of this is the git CLI, where you type:
git subcommand [optional flags]
For example:
git commit -am "My commit message"
Here, the command is git, the sub-command is commit, and the flags and argument(s) are
-a, -m and "My commit message" (the argument for -m).
Subcommands are not always required, especially in the case of a simple CLI, but can provide a nice way to structure your program and make its interface easy to understand.
Required vs optional input π
The inputs to your CLI are its user interface. Keeping them comprehensible and easy to understand is a benefit to both your users and to you, the designer and maintainer of the CLI. Some reasonable rules help to thwart interface chaos:
If a command or argument is required to perfom a given function, it should be either a positional argument or a sub-command name. Avoid cases where flags are required input! In some cases, an optional flag may be required when using another optional flag, but these conditions should be minimized where possible.
Reasonable defaults should be chosen for commands so that extra flags aren't required for typical (designed) use of your CLI. This makes it easier for your users by allowing them to input the minimal amount of information in order to get the CLI to function as expected.
Flags should be reserved for optional (which, by extension, should represent non-typical) use of the given command or sub-command.
Designing flags and switches π
Flags and switches represent the optional parts of your CLI interface, providing additional capability to users beyond the CLI's default behavior.
Here are what I consider to be best practices:
CLI flags (switches) may provide both a long and/or short form. For example, the --help command
typically uses -h as the "short" form. A --version flag might use either -v or -V.
CLI success or error codes π
A CLI will produce a return code to the environment it's run within: Typically 0 (zero) to signal successful completion of the task, or any non-zero integer for unsuccessful completion.
In C, this code is what's returned from the main function:
int main(int argc, char** argv) {
int retval = 0;
/* Maybe something happens that changes 'retval' to a non-zero state...? */
return retval;
}
In other languages, it's returned by the main process, in whatever form provided by that language.
Return codes 126 and above have particular meanings in a Linux/Unix shell, so shouldn't be reported by your CLI. However, that leaves plenty of other numbers to choose from! Many programs will only return a generic result of 1 when an error occurs.
Help text π
Help text should always be provided when the user enters either -h or --help. Additionally,
provide helpful instructions to the user if the user enters incorrect input.
If -h or --help is used, then print help based on the amount of command/sub-command completion
provided. In other words, if I type to the terminal:
dhop forget --help
I expect to get help about the dhop forget command/subcommand, not general help for dhop.
If the user, instead, tries to use the command but provides incorrect output, explain the problem
and any possible solutions. This may include printing the expected command inputs, or a reminder
to use --help to get the full help text. For example:
$ dhop forget unknown
ERROR: 'unkown' is not a named location! To get a list of named locations,
use 'dhop list'. Run 'dhop forget --help' for more information.
Help text format π
When designing help text for a command or sub-command, it's useful to provide some common sections:
- Description
Provide a brief description of your CLI or sub-command as directly and in as few words as possible.
- Usage
The "Usage" section should describes the interface of your CLI at the current sub-command level.
Required arguments should be described here.
- Flags
Provide a list of optional flags that modify the default behavior at the current command level. Each flag should include its long and short form.
- Subcommands
If there are any subcommands at this level of your CLI's interface, then describe them, providing a short description of each subcommand (a longer description can be provided when the user uses
--helpfor that subcommand).
Read more π
Further articles on the subject of CLI design:
External resources π
Oft-cited and worth reading:
