6

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.

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

2 Answers 2

3

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
1

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
1
  • 1
    It is an odd interaction, but it only applies to @ not other characters in COMP_WORDBREAKS like =. @ is a readline special too, I suspect it may be so that the completion works the same way as with readline (C-x @) which preserves a leading @ if present. Alt workaround is to check if ${COMP_WORDS[COMP_CWORD-1]} contains only "@" and use compgen ... -P @ to prefix it to the generated completions. bash-completion works around this with "shopt -u hostcomplete" which does other internal things but also removes "@" from COMP_WORDBREAKS. Commented Dec 22, 2017 at 12:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .