Tab completion is a ubiqutious time-saver, and I use it everywhere I can. Here’s how I set it up to autocomplete hostnames when I use the ssh or scp commands.

With tab completion in place, I can just type:

$ ssh <tab>

And be presented with a list of known hosts in my ~/.ssh/known_hosts file, or any hosts in my ~/.ssh/config file.

$ ssh <tab>
alex
alex.petdance.com
birdie
bogey
bonilla
cacti
champ
etc etc etc

Like all tab completion, I can just type the first letter and <tab> and get a shortened list:

$ ssh g<tab>
git.petdance.com  github.com        gitlab.com

I had found an ssh autocompletion script long ago, but it only took hostnames from ~/.ssh/known_hosts, and I wanted it to also include host aliases from my ~/.ssh/config file. I added the config file parsing, had a little fight with the compgen command, but now have it working.

Here’s the magic I had to add to my bash startup.

__complete_ssh_host() {
    local KNOWN_FILE=~/.ssh/known_hosts
    if [ -r $KNOWN_FILE ] ; then
        local KNOWN_LIST=`cut -f 1 -d ' ' $KNOWN_FILE | cut -f 1 -d ',' | grep -v '^[0-9[]'`
    fi

    local CONFIG_FILE=~/.ssh/config
    if [ -r $CONFIG_FILE ] ; then
        local CONFIG_LIST=`awk '/^Host [A-Za-z]+/ {print $2}' $CONFIG_FILE`
    fi

    local PARTIAL_WORD="${COMP_WORDS[COMP_CWORD]}";

    COMPREPLY=( $(compgen -W "$KNOWN_LIST$IFS$CONFIG_LIST" -- "$PARTIAL_WORD") )

    return 0
}

complete -F __complete_ssh_host ssh
complete -f -F __complete_ssh_host scp

The first complete line tells bash that whenever I type the ssh command and hit <tab> bash should run the function __complete_ssh_host to get a list of possible hosts to present as autocomplete targets.

The __complete_ssh_host looks in the ~/.ssh/known_hosts file to extract all the non-IP hostnames it can find, and then looks in ~/.ssh/config for hostnames. Then, it passes those hostnames and the partial word you’ve typed so far to the compgen command.

compgen takes a list of things that you could autocomplete, plus whatever partial word you’ve already typed, and returns a list of valid autocompletions. Try it from the shell prompt.

$ compgen -W 'aardvark apple baseball boogie cat' -- a
aardvark
apple

Here, I’m supplying a list of words, and then after the --, the start of a word, the letter a. compgen replies that the options that are possible are aardvark and apple.

This compgen was confusing, but now that I’ve figured out how to use it correctly, it makes perfect sense. I wish that the bash manual had an illustrative example like this one, which would have made everything immediately clear. I hope that my example here will make it clear for someone else.