SSH Host Completion – zsh Stylee
by Mez on Dec.06, 2009, under Personal
Ok, so recently, Richard Johnson and Michael Lustfield blogged about tab completion for SSH hosts.
I’m an avid user of zsh, and have my own way of doing this (liberally stolen from Daniel Silverstone).
Now, this requires a little setup to start with, as some Linux Distributions have a habit of creating “hashed” known_hosts files. So, what I’ve done, is before I ever SSH into a host, I add the following line to my ~/.ssh/config
HashKnownHosts no
From here, I can then add the following line to my ~/.zshrc
zstyle -e ':completion::*:*:*:hosts' hosts 'reply=(${=${${(f)"$(cat {/etc/ssh_,~/.ssh/known_}hosts(|2)(N) /dev/null)"}%%[# ]*}//,/ })'
Now, when I try and ssh into a host, I can use tab completion to complete any host I’ve previously ssh’d into and any new hosts I ssh into get automatically added to the list
December 6th, 2009 on 1:47 pm
Cute.
To be fair, you should note why “hashed” known_hosts files are a good idea: an attacker getting hold of your account (at the moment your secret key is “unlocked”) will have a nice directory of hosts to try next.
That’s why it was introduced in the first place.
So whoever follows your advice should take this into consideration to strike the correct tradeoff.
Regards
– tomás
December 6th, 2009 on 8:34 pm
As far as I can see zsh does this by default?
I don’t see why you need that zstyle call in zshrc.
December 6th, 2009 on 10:11 pm
I do not know if you are familiar with grml.org/zsh If not you should give a try.
regards,
cstamas
December 6th, 2009 on 11:42 pm
Why so ugly, and inflexible?
if [ -f ~/.ssh/known_hosts ]; then
hosts=(`awk ‘{print $1}’ ~/.ssh/known_hosts | tr ‘,’ ‘\n’ `)
fi
if [ -f ~/.ssh/config ]; then
hosts=($hosts `grep ^Host ~/.ssh/config | sed s/Host\ // | egrep -v ‘^\*$’`)
fi
if [ -f /var/lib/misc/ssh_known_hosts ]; then
hosts=($hosts `awk -F “[, ]” ‘{print $1}’ /var/lib/misc/ssh_known_hosts | sort -u`)
fi
if [ "$hosts" ]; then
zstyle ‘:completion:*:hosts’ hosts $hosts
fi
December 7th, 2009 on 7:12 am
Really nice, Martin! =:) I can’t do without zsh and the stupid hashed known_hosts file has been irking me for quite a while. Thanks for sharing!! =:)
July 7th, 2010 on 8:04 pm
BTW- The correct link for my blog:
http://profarius.com/content/ssh-tab-complete
Josip: That is.. Ugly..
[[ -f ~/.ssh/known_hosts ]] && hosts=(`awk ‘{print $1}’ ~/.ssh/known_hosts | tr ‘,’ ‘\n’ `)
[[ -f ~/.ssh/config ]] && hosts=($hosts `grep ^Host ~/.ssh/config | sed s/Host\ // | egrep -v ‘^\*$’`)
[[ -f /var/lib/misc/ssh_known_hosts ]] && hosts=($hosts `awk -F “[, ]” ‘{print $1}’ /var/lib/misc/ssh_known_hosts | sort -u`)
[[ "$hosts" ]] && zstyle ‘:completion:*:hosts’ hosts $hosts
Upi could also make each line into a single sed statement rather than all the pipes.
September 27th, 2011 on 10:47 am
Way cleaner way to do it I believe is:
hosts=$(awk ‘/^Host / {printf(“%s “,$2)}’ ~/.ssh/config 2>/dev/null)
zstyle ‘:completion:*:hosts’ hosts $hosts