SSH Config Host Autocomplete Command not Autocompleting

I wrote a function to get my hosts from ssh config without getting wildcard hosts:

sshConfAutoComplete() { 
   cat ~/.ssh/config | 
   grep 'host '      | 
   sed '
     s#.**##g; 
     s#host ##g
   '
}

Output:

pi
lynx
iridium
batchelorantor
rasp

The output is correct, so I added this function to:
/usr/local/etc/bash_completion.d/ssh

Like this:

sshConfAutoComplete() { 
   cat ~/.ssh/config | 
   grep 'host '      | 
   sed '
     s#.**##g; 
     s#host ##g
   '
}
complete -F sshConfAutoComplete ssh

Then I added this source: . /usr/local/etc/bash_completion.d/ssh to ~/.bash_profile

Sourced ~/bash_profile, then when I type ssh <tab> the following comes up:

pi
lynx
iridium
batchelorantor
rasp

If I type ssh ly <tab> it doesn’t autocomplete to lynx, it just outputs the above.

How do I fix this?

Asked By: Nickotine

||

In man bash the section headed Programmable Completion explains how the
function called by -F needs to provide the matching results in the array
variable COMPREPLY. Typically the full list as provided by your sed
commands are passed to the command compgen -W for it to try matching the
words against the target word, which is arg 2 ($2) of your function.
Simplifying a little we get:

sshConfAutoComplete() { 
   COMPREPLY=( $(compgen -W 
    "$(sed -n ' /host /{s#.**##g; s#host ##g; p} ' ~/.ssh/config)" -- "$2"))
}
complete -F sshConfAutoComplete ssh

For MacOS the standard sed command does not accept ; so each command must be on a new line:

   COMPREPLY=( $(compgen -W 
    "$(sed -n '/^host /{
     s#.**##g
     s#host ##g
     p
    }' ~/.ssh/config)" -- "$2"))
Answered By: meuh

I got it working doing this and adding it my ~/bash_profile:

IFS=$'n'

getSshConfHosts() {                                                                                                                                              
  grep    '^host' ~/.ssh/config  |                                                                                                                                   
  grep -v '[?*]'                 |                                                                                                                                       
  cut -d ' ' -f 2-                                                                                                                                       
}

sshConfAutoComplete() {                                                                                                                                          
    local cur prev opts                                                                                                                                                                
    cur=${COMP_WORDS[COMP_CWORD]}                                                                                                                                                                  
    prev=${COMP_WORDS[COMP_CWORD-1]}                                                                                                                                  
    opts=$(getSshConfHosts)                                                                                                                                                       
    COMPREPLY=( $(compgen -W "$opts" -- $cur ) )                                                                                                     
}         
complete -F sshConfAutoComplete ssh

My previous sed command left a blank line at the deletion of host *

Update

This answer works, but I gave it to the accepted answer as he didn’t know I was on Mac, and he hadn’t written it first. His version is much easier to understand.

I use the regex part in another function so I have it like this in my bash_profile:

IFS=$'n'

getSshConfHosts() {
   sed -n '/^host /{
     s#.**##g
     s#host ##g; p
   }' ~/.ssh/config
}

sshConfAutoComplete() {
    local wordList
    wordList=$(getSshConfHosts)
    COMPREPLY=( $(compgen -W "$wordList" -- $2 ) )
}
complete -F sshConfAutoComplete ssh
Answered By: Nickotine
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.