One of the much-less-well-known-than-should-be features of the GNU Bourne-Again Shell (bash) is its programmable completion functions. The default tab-completion can be extended to cover any number of external commands. For example:

[jk@pokey nfsim]$ make <TAB><TAB>
TAGS          distclean     import        savelinks
all           docs          importclean   simulator
check         gcov          install       snapshot
clean         gcov-clean    restorelinks  tags
[jk@pokey nfsim]$ make 

Here, the completion code has found that we're using make, and parsed the Makefile (in the current directory) to find available targets, displaying the available options.

For a more impressive example:

[jk@pokey ~]$ scp b1:kernel/<TAB><TAB>
kernel/linus/          kernel/patches/
kernel/modules/        kernel/powerpc-merge/
[jk@pokey ~]$ scp b1:kernel/

The completion code has ssh-ed into the remote machine to find the possible file-based completions for the scp command.

Neat, huh?

getting it working

The advanced completions aren't (usually) enabled by default, but it's easy to do so. The Debian and Ubuntu distributions ship bash with a default set of completions in /etc/bash_completion, which you can just source into the current shell:

[jk@pokey ~]$ . /etc/bash_completion

Now go crazy with the tab key.

To save having to source the completion file in every new shell, I have the following fragment in my .bashrc:

if [ -f /etc/bash_completion ]; then
        . /etc/bash_completion

adding completions

Being programmable, the programmable completions can be quite easily extended for other commands.

For example, I have a k42make command, which will copy a k42 tree to a predefined remote machine, then ssh to that machine and run make. Because the arguments provided to k42make are passed directly to the remote make, it would be great to provide the same completions as the make command (possible because the Makefile is available locally). We can define the k42make command to use the existing _make function to generate expansions:

[jk@pokey ~]$ complete -F _make -o filenames k42make

As another example: I have a command called kdo, which runs a command, waits for it to complete and displays a KDE dialog when it's done (see michael's blog for the reasoning behind this). We can complete on available commands, just the same as with strace, exec or time, using the _command function:

[jk@pokey ~]$ complete -F _command -o filenames kdo

The last part of the previous section was an oversimplification - this is what I really have in my .bashrc:

if [ -f /etc/bash_completion ]; then
        . /etc/bash_completion
        # local completions
        complete -F _command -o filenames kdo
        complete -F _make -o filenames k42make

package maintainers

The /etc/bash_completion script is extensible - after defining its own completions, it includes any files in the /etc/bash_completion.d/ directory. So, any installed package can (and should!) drop a file in there, defining possible expansions for command-line utilities.