<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title>Comments on: SSH tab completion</title>
	<atom:link href="http://plathrop.tertiusfamily.net/blog/2008/03/24/ssh-tab-completion/feed/" rel="self" type="application/rss+xml" />
	<link>http://plathrop.tertiusfamily.net/blog/2008/03/24/ssh-tab-completion/</link>
	<description>Paul Lathrop discusses systems administration.</description>
	<pubDate>Thu, 20 Nov 2008 13:51:38 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
		<item>
		<title>By: AJ</title>
		<link>http://plathrop.tertiusfamily.net/blog/2008/03/24/ssh-tab-completion/#comment-653</link>
		<dc:creator>AJ</dc:creator>
		<pubDate>Mon, 17 Nov 2008 03:46:48 +0000</pubDate>
		<guid isPermaLink="false">http://plathrop.tertiusfamily.net/blog/2008/03/24/ssh-tab-completion/#comment-653</guid>
		<description>From Ubuntu 7.04+'s /etc/bash_completion:

&lt;code&gt;
_known_hosts()
{
       local cur curd ocur user suffix aliases global_kh user_kh hosts i host
       local -a kh khd config

  COMPREPLY=()
  cur=`_get_cword`
  ocur=$cur

  [ "$1" = -a ] &#124;&#124; [ "$2" = -a ] &#38;&#38; aliases='yes'
  [ "$1" = -c ] &#124;&#124; [ "$2" = -c ] &#38;&#38; suffix=':'
  [[ $cur == *@* ]] &#38;&#38; user=${cur%@*}@ &#38;&#38; cur=${cur#*@}
  kh=()

  # ssh config files
  [ -r /etc/ssh/ssh_config ] &#38;&#38;
    config=( "${config[@]}" "/etc/ssh/ssh_config" )
  [ -r "${HOME}/.ssh/config" ] &#38;&#38;
    config=( "${config[@]}" "${HOME}/.ssh/config" )
  [ -r "${HOME}/.ssh2/config" ] &#38;&#38;
    config=( "${config[@]}" "${HOME}/.ssh2/config" )

  if [ ${#config[@]} -gt 0 ]; then
      # expand path (if present) to global known hosts file
      global_kh=$( eval echo $( sed -ne 's/^[ \t]*[Gg][Ll][Oo][Bb][Aa][Ll][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/\1/p' "${config[@]}" ) )
      # expand path (if present) to user known hosts file
      user_kh=$( eval echo $( sed -ne 's/^[ \t]*[Uu][Ss][Ee][Rr][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/\1/p' "${config[@]}" ) )
  fi

  # Global known_hosts files
  [ -r "$global_kh" ] &#38;&#38;
      kh=( "${kh[@]}" "$global_kh" )
  [ -r /etc/ssh/ssh_known_hosts ] &#38;&#38;
      kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts )
  [ -r /etc/ssh/ssh_known_hosts2 ] &#38;&#38;
      kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts2 )
  [ -r /etc/known_hosts ] &#38;&#38;
      kh=( "${kh[@]}" /etc/known_hosts )
  [ -r /etc/known_hosts2 ] &#38;&#38;
      kh=( "${kh[@]}" /etc/known_hosts2 )
  [ -d /etc/ssh2/knownhosts ] &#38;&#38;
      khd=( "${khd[@]}" /etc/ssh2/knownhosts/*pub )

  # User known_hosts files
  [ -r "$user_kh" ] &#38;&#38;
      kh=( "${kh[@]}" "$user_kh" )
  [ -r ~/.ssh/known_hosts ] &#38;&#38;
      kh=( "${kh[@]}" ~/.ssh/known_hosts )
  [ -r ~/.ssh/known_hosts2 ] &#38;&#38;
      kh=( "${kh[@]}" ~/.ssh/known_hosts2 )
  [ -d ~/.ssh2/hostkeys ] &#38;&#38;
      khd=( "${khd[@]}" ~/.ssh2/hostkeys/*pub )

  # If we have known_hosts files to use
  if [ ${#kh[@]} -gt 0 -o ${#khd[@]} -gt 0 ]; then
      # Escape slashes and dots in paths for awk
      cur=${cur//\//\\\/}
      cur=${cur//\./\\\.}
      curd=$cur

      if [[ "$cur" == [0-9]*.* ]]; then
    # Digits followed by a dot - just search for that
    cur="^$cur.*"
      elif [[ "$cur" == [0-9]* ]]; then
    # Digits followed by no dot - search for digits followed
    # by a dot
    cur="^$cur.*\."
      elif [ -z "$cur" ]; then
    # A blank - search for a dot or an alpha character
    cur="[a-z.]"
      else
    cur="^$cur"
      fi

      if [ ${#kh[@]} -gt 0 ]; then

    # FS needs to look for a comma separated list
    COMPREPLY=( $( awk 'BEGIN {FS=","}
        /^[^&#124;]/ {for (i=1; i/dev/null ) )
      fi
      if [ ${#khd[@]} -gt 0 ]; then
    # Needs to look for files called
    # .../.ssh2/key_22_.pub
    # dont fork any processes, because in a cluster environment,
    # there can be hundreds of hostkeys
    for i in "${khd[@]}" ; do
        if [[ "$i" == *key_22_$curd*.pub ]] &#38;&#38; [ -r "$i" ] ; then
      host=${i/#*key_22_/}
      host=${host/%.pub/}
      COMPREPLY=( "${COMPREPLY[@]}" $host )
        fi
    done
      fi

      # append any available aliases from config files
      if [ ${#config[@]} -gt 0 ] &#38;&#38; [ -n "$aliases" ]; then
    local host_aliases=$( sed -ne 's/^[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\?['"$'\t '"']\+\([^*?]*\)$/\2/p' "${config[@]}" )
    hosts=$( compgen -W "$host_aliases" -- $ocur )
    COMPREPLY=( "${COMPREPLY[@]}" $hosts )
      fi

      # Now add results of normal hostname completion
      COMPREPLY=( "${COMPREPLY[@]}" $( compgen -A hostname -- $ocur ) )

      # apply suffix
      for (( i=0; i &#60; ${#COMPREPLY[@]}; i++ )); do
    COMPREPLY[i]=$user${COMPREPLY[i]}$suffix
      done
  else
      # Just do normal hostname completion
      COMPREPLY=( $( compgen -A hostname -S "$suffix" -- $cur ) )
  fi

  return 0
}
&lt;/code&gt;

Although, simply enough, with recent versions of bash most will just need (bashrc):
# enable bash completion in interactive shells
if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi</description>
		<content:encoded><![CDATA[<p>From Ubuntu 7.04+&#8217;s /etc/bash_completion:</p>
<p><code><br />
_known_hosts()<br />
{<br />
       local cur curd ocur user suffix aliases global_kh user_kh hosts i host<br />
       local -a kh khd config</p>
<p>  COMPREPLY=()<br />
  cur=`_get_cword`<br />
  ocur=$cur</p>
<p>  [ "$1" = -a ] || [ "$2" = -a ] &amp;&amp; aliases=&#8217;yes&#8217;<br />
  [ "$1" = -c ] || [ "$2" = -c ] &amp;&amp; suffix=&#8217;:&#8217;<br />
  [[ $cur == *@* ]] &amp;&amp; user=${cur%@*}@ &amp;&amp; cur=${cur#*@}<br />
  kh=()</p>
<p>  # ssh config files<br />
  [ -r /etc/ssh/ssh_config ] &amp;&amp;<br />
    config=( &#8220;${config[@]}&#8221; &#8220;/etc/ssh/ssh_config&#8221; )<br />
  [ -r "${HOME}/.ssh/config" ] &amp;&amp;<br />
    config=( &#8220;${config[@]}&#8221; &#8220;${HOME}/.ssh/config&#8221; )<br />
  [ -r "${HOME}/.ssh2/config" ] &amp;&amp;<br />
    config=( &#8220;${config[@]}&#8221; &#8220;${HOME}/.ssh2/config&#8221; )</p>
<p>  if [ ${#config[@]} -gt 0 ]; then<br />
      # expand path (if present) to global known hosts file<br />
      global_kh=$( eval echo $( sed -ne &#8217;s/^[ \t]*[Gg][Ll][Oo][Bb][Aa][Ll][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/\1/p&#8217; &#8220;${config[@]}&#8221; ) )<br />
      # expand path (if present) to user known hosts file<br />
      user_kh=$( eval echo $( sed -ne &#8217;s/^[ \t]*[Uu][Ss][Ee][Rr][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee]['"$'\t '"']*\(.*\)$/\1/p&#8217; &#8220;${config[@]}&#8221; ) )<br />
  fi</p>
<p>  # Global known_hosts files<br />
  [ -r "$global_kh" ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; &#8220;$global_kh&#8221; )<br />
  [ -r /etc/ssh/ssh_known_hosts ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; /etc/ssh/ssh_known_hosts )<br />
  [ -r /etc/ssh/ssh_known_hosts2 ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; /etc/ssh/ssh_known_hosts2 )<br />
  [ -r /etc/known_hosts ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; /etc/known_hosts )<br />
  [ -r /etc/known_hosts2 ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; /etc/known_hosts2 )<br />
  [ -d /etc/ssh2/knownhosts ] &amp;&amp;<br />
      khd=( &#8220;${khd[@]}&#8221; /etc/ssh2/knownhosts/*pub )</p>
<p>  # User known_hosts files<br />
  [ -r "$user_kh" ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; &#8220;$user_kh&#8221; )<br />
  [ -r ~/.ssh/known_hosts ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; ~/.ssh/known_hosts )<br />
  [ -r ~/.ssh/known_hosts2 ] &amp;&amp;<br />
      kh=( &#8220;${kh[@]}&#8221; ~/.ssh/known_hosts2 )<br />
  [ -d ~/.ssh2/hostkeys ] &amp;&amp;<br />
      khd=( &#8220;${khd[@]}&#8221; ~/.ssh2/hostkeys/*pub )</p>
<p>  # If we have known_hosts files to use<br />
  if [ ${#kh[@]} -gt 0 -o ${#khd[@]} -gt 0 ]; then<br />
      # Escape slashes and dots in paths for awk<br />
      cur=${cur//\//\\\/}<br />
      cur=${cur//\./\\\.}<br />
      curd=$cur</p>
<p>      if [[ "$cur" == [0-9]*.* ]]; then<br />
    # Digits followed by a dot - just search for that<br />
    cur=&#8221;^$cur.*&#8221;<br />
      elif [[ "$cur" == [0-9]* ]]; then<br />
    # Digits followed by no dot - search for digits followed<br />
    # by a dot<br />
    cur=&#8221;^$cur.*\.&#8221;<br />
      elif [ -z "$cur" ]; then<br />
    # A blank - search for a dot or an alpha character<br />
    cur=&#8221;[a-z.]&#8221;<br />
      else<br />
    cur=&#8221;^$cur&#8221;<br />
      fi</p>
<p>      if [ ${#kh[@]} -gt 0 ]; then</p>
<p>    # FS needs to look for a comma separated list<br />
    COMPREPLY=( $( awk &#8216;BEGIN {FS=&#8221;,&#8221;}<br />
        /^[^|]/ {for (i=1; i/dev/null ) )<br />
      fi<br />
      if [ ${#khd[@]} -gt 0 ]; then<br />
    # Needs to look for files called<br />
    # &#8230;/.ssh2/key_22_.pub<br />
    # dont fork any processes, because in a cluster environment,<br />
    # there can be hundreds of hostkeys<br />
    for i in &#8220;${khd[@]}&#8221; ; do<br />
        if [[ "$i" == *key_22_$curd*.pub ]] &amp;&amp; [ -r "$i" ] ; then<br />
      host=${i/#*key_22_/}<br />
      host=${host/%.pub/}<br />
      COMPREPLY=( &#8220;${COMPREPLY[@]}&#8221; $host )<br />
        fi<br />
    done<br />
      fi</p>
<p>      # append any available aliases from config files<br />
      if [ ${#config[@]} -gt 0 ] &amp;&amp; [ -n "$aliases" ]; then<br />
    local host_aliases=$( sed -ne &#8217;s/^[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\?['"$'\t '"']\+\([^*?]*\)$/\2/p&#8217; &#8220;${config[@]}&#8221; )<br />
    hosts=$( compgen -W &#8220;$host_aliases&#8221; &#8212; $ocur )<br />
    COMPREPLY=( &#8220;${COMPREPLY[@]}&#8221; $hosts )<br />
      fi</p>
<p>      # Now add results of normal hostname completion<br />
      COMPREPLY=( &#8220;${COMPREPLY[@]}&#8221; $( compgen -A hostname &#8212; $ocur ) )</p>
<p>      # apply suffix<br />
      for (( i=0; i &lt; ${#COMPREPLY[@]}; i++ )); do<br />
    COMPREPLY[i]=$user${COMPREPLY[i]}$suffix<br />
      done<br />
  else<br />
      # Just do normal hostname completion<br />
      COMPREPLY=( $( compgen -A hostname -S &#8220;$suffix&#8221; &#8212; $cur ) )<br />
  fi</p>
<p>  return 0<br />
}<br />
</code></p>
<p>Although, simply enough, with recent versions of bash most will just need (bashrc):<br />
# enable bash completion in interactive shells<br />
if [ -f /etc/bash_completion ]; then<br />
    . /etc/bash_completion<br />
fi</p>
]]></content:encoded>
	</item>
</channel>
</rss>
