SSH – How to Edit Command Completion for SSH on Zsh

command-line-interfaceshellsshzsh

I'd like to set up command completion on zsh to display host names after I type

ssh [TAB]

taking the names out of my .ssh/config file (and preferably from known_hosts and /etc/hosts and anywhere else that makes sense) and presenting one single list.

It does some of this currently, but

  1. it doesn't use .ssh/config at all
  2. it requires a username first, even though using .ssh/config makes typing usernames unnecessary
  3. it presents multiple lists (probably one from known_hosts and another from /etc/hosts, but I haven't verified that)

So I want to be include known usernames as well as known hostnames in the (preferably single) list after typing ssh [TAB]

(I'm coming here before Google because 1) it'll result in the answer getting stored here, and 2) it's probably more efficient. If no one else answers, I'll hunt down the answer.)

Best Answer

Here's the relevant part from my .zshrc. It hasn't changed since 2002, so I might write it differently today, but it still works to complete host names from ~/.ssh/config and ~/.ssh/known_hosts (if HashKnownHosts is off — it didn't exist in those days).

h=()
if [[ -r ~/.ssh/config ]]; then
  h=($h ${${${(@M)${(f)"$(cat ~/.ssh/config)"}:#Host *}#Host }:#*[*?]*})
fi
if [[ -r ~/.ssh/known_hosts ]]; then
  h=($h ${${${(f)"$(cat ~/.ssh/known_hosts{,2} || true)"}%%\ *}%%,*}) 2>/dev/null
fi
if [[ $#h -gt 0 ]]; then
  zstyle ':completion:*:ssh:*' hosts $h
  zstyle ':completion:*:slogin:*' hosts $h
fi