ZSH Autocomplete with SSH Config File

If you do any kind of web work for a living, you probably deal with ssh on a daily basis. You also probably have multiple servers that you need to ssh into at any given time. If you’re like me, you probably don’t like wasting time trying to figure out ssh params (did the ip address end in 173 or 137?). Well in recent times I’ve found that the built in ssh config file has some pretty awesome capabilities as well as ZSH has some nice autocompletion to boot. Together they make a pretty good workflow and you can spend time solving problems and not remembers ports and ip addresses.

Alias the SSH command

It might seem like over-engineering but ever since I really started getting into using bash aliases I’ve followed a personal rule that any command that I use on a daily basis should be as few keystrokes as possible. Even though it’s only saving 2 keystrokes I still keep this alias in my ~/.zshrc file:

alias s='ssh'

Get Some ZSH Autocomplete

Tab completion is your best friend when it comes to the command line, utilize it. ZSH has a very extensive autocomplete system which can be a little difficult to grasp but I’ve pulled out the essential parts out my zshrc to give a quick snippet which will give you full ssh autocompletion:

# Highlight the current autocomplete option
zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"

# Better SSH/Rsync/SCP Autocomplete
zstyle ':completion:*:(scp|rsync):*' tag-order ' hosts:-ipaddr:ip\ address hosts:-host:host files'
zstyle ':completion:*:(ssh|scp|rsync):*:hosts-host' ignored-patterns '*(.|:)*' loopback ip6-loopback localhost ip6-localhost broadcasthost
zstyle ':completion:*:(ssh|scp|rsync):*:hosts-ipaddr' ignored-patterns '^(<->.<->.<->.<->|(|::)([[:xdigit:].]##:(#c,2))##(|%*))' '127.0.0.<->' '255.255.255.255' '::1' 'fe80::*'

# Allow for autocomplete to be case insensitive
zstyle ':completion:*' matcher-list '' 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' \
  '+l:|?=** r:|?=**'

# Initialize the autocompletion
autoload -Uz compinit && compinit -i

This snippet by itself is decent enough but where it really comes in handy is when you pair is with the ssh config file.

The Magic Config File

I actually didn’t know about this for a long time, way longer than I should have. Previously the most I’d ever done with my config file was adding options to maximize the life of my ssh connections. But then something spectacular happened, I learned you could use the config file to store your server’s ssh information. But first off, you’re going to need a config file so make sure that you got one by running the following command:

touch ~/.ssh/config

Alright, now before now you’ve probably been typing in a string similar to the following to initiate a server connection:

ssh myuser@myserver.com

or if you have ssh running on a different port:

ssh myuser@myserver.com -p 31313

This works for a while, maybe you have a 2 or 3 servers and it’s super easy to remember all the information. But what happens when you bump up to 50 or 100 servers? Chances are that you won’t have such an easy time remembering all the servers’ information, especially if they have different setups. Using the previous ssh command you can add the following snippet to your ~/.ssh/config file:

Host servername
    Hostname myserver.com
    User myuser
    Port 31313

And now when you want to connect to that server you can type, (Remembering that I’ve aliased ’s’ to ‘ssh’):

s servername

and you will connect to your server. Now servername can be any name that you want it to be it doesn’t have to be anything related to the server. The best part now is with the ZSH autocompletion in the previous section you can type:

s s<tab>
s servername

Whamo! Minimizing keystrokes. Now you create an entry for each server and have a much easier time connecting to each one without having to remember and of the ssh information.