Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I found the following script (for bash) that enables me to get tab completion for any hostname I've connected to (from ~/.ssh/known_hosts):

complete -W "$(echo `cat ~/.ssh/known_hosts | cut -f 1 -d ' ' | sed -e s/,.*//g | uniq | grep -v "\["`;)" ssh

However, the problem is that the tab completion doesn't work after I've typed a username.

How can I improve this so if I type...

ssh myusername@my 

and expect it to complete "myhostname.com" it will be able to do so?

It would be even better if it could tab whole strings (user@hostname) as well, but I can live with either option. Without the first, this isn't much use unless my host username matches the local username.

share|improve this question
    
Haven't we all learned in school to frown upon backticks, unless visiting a Unix museum, and that $() can be nested?! :) Still +1 –  0xC0000022L Sep 12 '13 at 18:40
    
@0xC0000022L Eek, sorry, I was much newer at bash when I wrote this question. –  NickC Sep 12 '13 at 19:51
add comment

2 Answers

The known_hosts file by default usually contains hashed entries which bash_completion can't parse.

You can edit your ssh_config (/etc/ssh/ssh_config) to set:

HashKnownHosts no

Then you'll probably need to clear your current known hosts file:

> ~/.ssh/known_hosts
share|improve this answer
add comment

If $COMP_WORDBREAKS contains "@" (that is the default on my system) then serious problems arise which I could not solve (after pressing Tab and Enter one "@" was removed).

But if you delete it from that environment variable then this works:

_foo () {
  if [[ "$COMP_WORDBREAKS" =~ "@" ]]; then
    echo ""
    echo '$COMP_WORDBREAKS contains "@"; aborting'
    COMPREPLY=()
  else
    at_in=no
    if [[ ${COMP_WORDS[COMP_CWORD]} =~ "@" ]]; then
      var="${COMP_WORDS[COMP_CWORD]}"
      tail="${var#*@}"
      prefix="${var%"$tail"}"
    else
      prefix=""
    fi
    COMPREPLY=($(cut -f 1 -d ' ' <~/.ssh/known_hosts |
      sed -e 's/,/\n/g' | uniq |
      awk -v prefix="${prefix}" '/\[/ {next}; {print prefix $0;}'))
    COMPREPLY=($(compgen -W "${COMPREPLY[*]}" "${COMP_WORDS[COMP_CWORD]}"))
  fi
}

complete -F _foo ssh
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.