Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Integralist/0500e6b5aabf95034cd83eff8c9e2ead to your computer and use it in GitHub Desktop.
Save Integralist/0500e6b5aabf95034cd83eff8c9e2ead to your computer and use it in GitHub Desktop.
[bash autocomplete for your custom programs] #bash #shell #autocomplete

Here's an example taken from the https://github.com/fastly/cli

_fastly_bash_autocomplete() {
    local cur prev opts base
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    opts=$( ${COMP_WORDS[0]} --completion-bash ${COMP_WORDS[@]:1:$COMP_CWORD} )
    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
    return 0
}
complete -F _fastly_bash_autocomplete fastly

Notice the last line is what sets up the bash autocomplete and says whenever the user types fastly and then <Tab> to call the shell function _fastly_bash_autocomplete.

That function then sets an environment variable COMPREPLY to contain a list of values that should be returned to the user.

That list is generated by evaluating a separate command called compgen and passing it the list of available options to present to the user.

The available opts are stored in the local variable opts and that is produced by executing the fastly binary (i.e. ${COMP_WORDS[0]}) and passing it a flag that the binary knows how to handle (i.e. --completion-bash).

One of the nicest facilities of the modern shell is the built in "completion" support. These facilities allow you to complete commands and their arguments easily. Read on for a brief introduction to adding your own command completions.

Most shells allow command completion, typically bound to the TAB key, which allow you to complete the names of commands stored upon your PATH, file names, or directory names. This is typically used like so:

ls /bo[TAB]

When you press the TAB key the argument /bo is automatically replaced with the value /boot.

Recently some shells have started allowing you to do even more: completing arguments to commands. Two notable shells which allow this are zsh, and bash. Since I'm a bash user I'm only going to cover that.

The Debian bash package supplies a command line completion file /etc/bash_completion which sets up some common support.

If you're not using it right now you can load it by typing into your shell ". /etc/bash_completion" as shown here:

skx@lappy:~$ . /etc/bash_completion
skx@lappy:~$

Once this is done you'll be able to TAB-complete many common arguments to programs, for example:

skx@lappy:~$ apt-get upd[TAB]
skx@lappy:~$ apt-get upg[TAB]

But how do you extend the support yourself? Well the completion routines supplied make use of several internal bash commands such as complete. These can be used by your own shell startup files, or more easily by creating a small file and dropping it into the directory /etc/bash_completion.d/.

When the bash_completion file is sourced (or loaded) everything inside the /etc/bash_completion.d directory is also loaded. This makes it a simple matter to add your own hooks.

One of the things which bash allows you to complete is hostnames, this can be very useful for some commands.

I remotely manage some computers using VNC and I usually do that by running the command "xvncviewer hostname".

To allow bash to complete the hostname fragment I type with we'll use the complete command to tell it that xvncviewer requires a hostname:

skx@lappy:~$ complete -F _known_hosts xvncviewer

Once I've done this I can type [TAB] to complete hostnames:

skx@lappy:~$ xvncviewer s[TAB]
savannah.gnu.org            ssh.tardis.ed.ac.uk
scratchy                    steve.org.uk
security.debian.org         security-master.debian.org
sun
skx@lappy:~$ xvncviewer sc[TAB]

This has now completed the hostname scratchy for me.

The function _known_hosts is defined in the file /etc/bash_completion. How did I know I could use it? By using the command "complete -p" to display all of the bindings in use:

skx@lappy:~$ complete -p
....
complete -F _known_hosts tracepath6
complete -F _known_hosts host
...

So what have we learnt so far?

Command line completion exists.
Completion is implemented in the file /etc/bash_completion
New completion commands may be placed inside the directory /etc/bash_completion.d
We can list all the current completion routines bound via "complete -p"

In part two we'll look at defining custom command line handling routines - similar to those already in place. So we can add command line completion to our own programs, or commands not yet covered.

Until then you might want to experiment a little yourself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment