Consider verbose 'usage' messages for infrequently used scripts

02:54 AM · Oct 15, 2026

On Unix systems, we all know those usage messages that programs dump out when you get something wrong about invoking them. For example, one of our local script's usage message is:

usage: setup-host-netboot [-Fn] [-e MAC] [-N|-H] HOST VERSION

This is a perfectly cromulent Unix style usage message, but it's not exactly helpful unless you remember a fair amount about using the script. In my view, this makes it a good usage message for a certain sort of script and a bad usage message for another sort.

If you use a script regularly and it has the kind of command line options that you might get slightly wrong (as this one does), a terse usage message is a good way to jog your memory without overwhelming you with a wall of text when you get something wrong. You can also pretty much guess what some of these things mean from context, like '-e MAC' (in context for this script, explicitly giving an Ethernet address) and '-n' (which we certainly hope is for a dry-run option, since '-n' is relatively standard for this).

However, sometimes you have scripts that you don't expect to run regularly and that have more ways they can be used, with more complicated command line options. It's possible to boil these down into a Unix style single line usage message, but it gets increasingly terse, opaque, and not terribly useful. For example, you could write a usage message like this:

usage: cs-resctl dns|domain|iface|iface-short [IP ... | SEARCH ...]

This usage message is technically correct but probably not useful in practice. If you're staring at this usage message it's not because you've used the wrong letter for an option and merely need a reminder of what the right letters are; instead, it's probably because you've forgotten how to do what you want with this script. Either you're running the script with no options in the hope of some enlightenment or you've remembered the usage wrong from the last time (which was months ago).

My view is that for this sort of script, its usage message should be more verbose, perhaps a lot more verbose (much like your error messages should be more verbose). For example, you might write a usage message that looks like this:

usage: cs-resctl dns|domain|iface|iface-short|help [<args>]
 set DNS servers: cs-resctl dns IP [IP ...]
 set search domains: cs-resctl domain DOMAIN [DOMAIN ...]
 see current servers or search domains: cs-resctl dns|domain
 see host interface: cs-resctl iface|iface-short

(Maybe this message should also say that the script is a frontend to resolvectl. It exists because have to give resolvectl the right network interface name, which vary across our servers.)

This usage message isn't everything that could be said about using the script, but I have to draw the line somewhere. Additional information can always be put in some explicit help text, such as you could get with 'cs-resctl help' (which should get mentioned explicitly in the basic usage stuff). Some people would put everything into the explicit 'help' output and restrict the core usage to two lines (one for usage, one to point you to the extended help), but I think that's too minimal for this sort of infrequently used scripts. If I'm mostly going to need to re-run the command with the 'help' option to get what I need, then I should put that information in the initial output to save time and aggravation.

If this sort of verbose usage message feels wrong, one thing you can do is to only print a verbose message if the script is being run in an interactive situation. A decent heuristic for detecting this is to see if standard input or standard output (or both) is connected to a terminal. If they aren't, you can print a terse message so that the cron job, pipeline, mass run across many of your machines or the like doesn't explode into a mass of text.