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.

  • 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. – Nicole Sep 12 '13 at 19:51
2

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
    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. – mr.spuratic Dec 22 '17 at 12:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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