I’m late adopter of bash completion. I tried it a few times but I always gave up because I found it slow. And I hate when it blocks my shell waiting for a command to finish. I’ve recently upgraded my computers and on recent hardware, it now runs pretty smoothly. So it’s time to give it another go.
One feature I use the most is ssh host completion. At work I work with a lot
of VMs. There is no way I can remember all of their IPs but it’s pretty easy to
put a name on each machine relevant enough to remember.
This has to be done in ~/.ssh/config, for example:
Host webserver
User myuser
Hostname xx.xx.xx.xx
with these lines, calling:
$ ssh webserver
is the same as calling:
$ ssh myuser@xx.xx.xx.xx
That hostname alias for ssh can be auto-completed hitting tab which makes it
super useful. This trick also works for any ssh aware program like: rsync,
sshfs, scp etc…
But what if I want to use that same hostname with a non ssh aware program ? I
would need a way to convert that hostname into the corresponding IP address of
the ~/.ssh/config file.
It seems to be possible to have a user /etc/hosts file using the environment
variable HOSTALIASES as described in man gethostbyname.
I’ve tried this approach but I never managed to have it working properly. And
one problem with this solution is that you now have to maintain two files:
~/.ssh/config and that HOSTALIASES file.
So I came up with a small script:
ssh-host.sh
to output the Hostname corresponding to a Host in ~/.ssh/config.
$ ssh-host.sh webserver
xx.xx.xx.xx
With that script in your PATH it is now easy to write commands like:
$ curl https://$(ssh-host.sh webserver)
and have it using the IP address of the ~/.ssh/config file.
This is already cool but, of course, that trick wouldn’t be complete without a bit of auto-completion !
# Completion for ssh-host.sh
_complete()
{
if [ "${#COMP_WORDS[@]}" != "2" ]; then
return
fi
HOSTS=$(cat ~/.ssh/config | awk '/^Host / { print $2 }')
COMPREPLY=($(compgen -W "$HOSTS" "${COMP_WORDS[1]}"))
}
complete -F _complete ssh-host.shAdd these lines to your ~/.bashrc and the ssh-host.sh script now complete
just like ssh does.
With this simple script, I can now use the ~/.ssh/config file as a /etc/hosts
file at the cost of calling that intermediate script. And it is super handy in
my workflow !