12 Feb 2021, 20:00

How to do basic shell completion

So you wrote some dumb tool for your coworkers. It works, but no one can remember the dang arguments. Half of them use zsh, the other half use fish, the grumpy loudmouth uses bash, and the new hire uses something that sounds like a tolkein reference. The documentation for everything is garbage, stackoverflow is filled with lies, and most of the available examples take up six pages. Can’t you do this simply?

Yes.

Here are some minimum-viable-shell-completions for popular shells- just enough to make the <major command> <minor command> pattern work, you know, like git $command or aws $product $verb.

bash

The big kahuna, the default on Linux distributions, and the old default on OS X, before the GPL v3 and Apple’s Great Terror. There are, as you might expect, Many Ways To Do It, but my favorite, because it is simple & bloody minded, is good ‘ol complete-

:~$ complete -W "fee fi fo fum" giant
:~$ giant <tab>
fee  fi   fo   fum  

zsh

The New Hotness in 2005 (I know it dates to 1990), and the default on MacOS for the past few years. Here there are also Many Ways To Do it, but look, I’m not going to lie- I like the old, deprecated compctl, because I am old and deprecated. Also, you can bang this out in two lines instead of 2 paragraphs, and brevity is brilliance.

% declare -a _giant_commands=(fee fi fo fum)
% compctl -k _giant_commands giant
% giant <tab><tab>
fee  fi   fo   fum

fish

If you were too cool in 2005 to use something that worked, fish was the shell for you. That is still sort of true, because dealing with cross-shell compatibility is still slightly more of a hassle than you really want to put up with. It also uses the complete command for completion, but the documentation is better, and it’s totally different from bash’s.

> complete -c giant -a "fee fi fo fum"
> giant <tab>
fee  fi  fo  fum

elvish

If you like to get in fights on message boards lamenting the lack of structured streams in the shell, Elvish is the shell for you. It is very neat, and has a truly wild feature set, including a built-in multi-pane file manager. Definitely worth a look if you’re feeling like changing your workflow up.

> edit:completion:arg-completer[giant] = [@args]{
    possibilities = [fee fi fo fum]
    put $@possibilities
}

> giant <tab>
 COMPLETING argument
fee  fi  fo  fum

I’m really feeling the namespacing, if I’m being honest. It makes introspection of the shell configuration a lot less like dipping your face into a firehose.