Zsh: completion rules for ssh

autocompletezsh

in zsh, I can autocomplete hostnames from /etc/hosts, ie:

ssh f<TAB>

will offer completions for hosts starting with f.

This is configured in /usr/share/zsh/functions/Completion/Unix/_hosts:

local ipstrip='[:blank:]#[^[:blank:]]#'

zstyle -t ":completion:${curcontext}:hosts" use-ip && useip=yes
[[ -n $useip ]] && ipstrip=
if (( ${+commands[getent]} )); then
  _cache_hosts=(${(s: :)${(ps:\t:)${(f)~~"$(_call_program hosts getent hosts 2>/dev/null)"}##${~ipstrip}}})
else
  _cache_hosts=(${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##${~ipstrip}}})
fi

....

_hosts=( "$_cache_hosts[@]" )

however, it only works if /etc/hosts file has the format 'IP' 'hostname', ie:

192.168.1.4      foo.mydomain.com

it will not work if IP is missing:

                 foo.mydomain.com

How can I modify the completion script, so that hostnames without IP are also completed?

Completion of hostnames without IP from /etc/hosts works fine in bash_completion. So I am just trying to get the same behavior on zsh.

Best Answer

I'd recommend doing this, which would use your (and the system's) ssh known hosts file instead:

zstyle -e ':completion:*:(ssh|scp|sftp|rsh|rsync):hosts' hosts 'reply=(${=${${(f)"$(cat {/etc/ssh_,~/.ssh/known_}hosts(|2)(N) /dev/null)"}%%[# ]*}//,/ })'

If you're still wanting to use /etc/hosts instead:

strip='[:blank:]#[^[:blank:]]#'
zstyle -e ':completion:*:(ssh|scp|sftp|rsh|rsync):hosts' hosts 'reply=(${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##${~strip}}})'

Best of luck!

Related Question