Set up tab completion for ssh and scp
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.