<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<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>My thoughts on everything from Operations through Parenting and beyond.</description>
	<lastBuildDate>Tue, 18 May 2010 18:33:01 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>By: AJ</title>
		<link>http://plathrop.tertiusfamily.net/blog/2008/03/24/ssh-tab-completion/comment-page-1/#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+&#039;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

  [ &quot;$1&quot; = -a ] &#124;&#124; [ &quot;$2&quot; = -a ] &amp;&amp; aliases=&#039;yes&#039;
  [ &quot;$1&quot; = -c ] &#124;&#124; [ &quot;$2&quot; = -c ] &amp;&amp; suffix=&#039;:&#039;
  [[ $cur == *@* ]] &amp;&amp; user=${cur%@*}@ &amp;&amp; cur=${cur#*@}
  kh=()

  # ssh config files
  [ -r /etc/ssh/ssh_config ] &amp;&amp;
    config=( &quot;${config[@]}&quot; &quot;/etc/ssh/ssh_config&quot; )
  [ -r &quot;${HOME}/.ssh/config&quot; ] &amp;&amp;
    config=( &quot;${config[@]}&quot; &quot;${HOME}/.ssh/config&quot; )
  [ -r &quot;${HOME}/.ssh2/config&quot; ] &amp;&amp;
    config=( &quot;${config[@]}&quot; &quot;${HOME}/.ssh2/config&quot; )

  if [ ${#config[@]} -gt 0 ]; then
      # expand path (if present) to global known hosts file
      global_kh=$( eval echo $( sed -ne &#039;s/^[ \t]*[Gg][Ll][Oo][Bb][Aa][Ll][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][&#039;&quot;$&#039;\t &#039;&quot;&#039;]*\(.*\)$/\1/p&#039; &quot;${config[@]}&quot; ) )
      # expand path (if present) to user known hosts file
      user_kh=$( eval echo $( sed -ne &#039;s/^[ \t]*[Uu][Ss][Ee][Rr][Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][&#039;&quot;$&#039;\t &#039;&quot;&#039;]*\(.*\)$/\1/p&#039; &quot;${config[@]}&quot; ) )
  fi

  # Global known_hosts files
  [ -r &quot;$global_kh&quot; ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; &quot;$global_kh&quot; )
  [ -r /etc/ssh/ssh_known_hosts ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; /etc/ssh/ssh_known_hosts )
  [ -r /etc/ssh/ssh_known_hosts2 ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; /etc/ssh/ssh_known_hosts2 )
  [ -r /etc/known_hosts ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; /etc/known_hosts )
  [ -r /etc/known_hosts2 ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; /etc/known_hosts2 )
  [ -d /etc/ssh2/knownhosts ] &amp;&amp;
      khd=( &quot;${khd[@]}&quot; /etc/ssh2/knownhosts/*pub )

  # User known_hosts files
  [ -r &quot;$user_kh&quot; ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; &quot;$user_kh&quot; )
  [ -r ~/.ssh/known_hosts ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; ~/.ssh/known_hosts )
  [ -r ~/.ssh/known_hosts2 ] &amp;&amp;
      kh=( &quot;${kh[@]}&quot; ~/.ssh/known_hosts2 )
  [ -d ~/.ssh2/hostkeys ] &amp;&amp;
      khd=( &quot;${khd[@]}&quot; ~/.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 [[ &quot;$cur&quot; == [0-9]*.* ]]; then
    # Digits followed by a dot - just search for that
    cur=&quot;^$cur.*&quot;
      elif [[ &quot;$cur&quot; == [0-9]* ]]; then
    # Digits followed by no dot - search for digits followed
    # by a dot
    cur=&quot;^$cur.*\.&quot;
      elif [ -z &quot;$cur&quot; ]; then
    # A blank - search for a dot or an alpha character
    cur=&quot;[a-z.]&quot;
      else
    cur=&quot;^$cur&quot;
      fi

      if [ ${#kh[@]} -gt 0 ]; then

    # FS needs to look for a comma separated list
    COMPREPLY=( $( awk &#039;BEGIN {FS=&quot;,&quot;}
        /^[^&#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 &quot;${khd[@]}&quot; ; do
        if [[ &quot;$i&quot; == *key_22_$curd*.pub ]] &amp;&amp; [ -r &quot;$i&quot; ] ; then
      host=${i/#*key_22_/}
      host=${host/%.pub/}
      COMPREPLY=( &quot;${COMPREPLY[@]}&quot; $host )
        fi
    done
      fi

      # append any available aliases from config files
      if [ ${#config[@]} -gt 0 ] &amp;&amp; [ -n &quot;$aliases&quot; ]; then
    local host_aliases=$( sed -ne &#039;s/^[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\?[&#039;&quot;$&#039;\t &#039;&quot;&#039;]\+\([^*?]*\)$/\2/p&#039; &quot;${config[@]}&quot; )
    hosts=$( compgen -W &quot;$host_aliases&quot; -- $ocur )
    COMPREPLY=( &quot;${COMPREPLY[@]}&quot; $hosts )
      fi

      # Now add results of normal hostname completion
      COMPREPLY=( &quot;${COMPREPLY[@]}&quot; $( compgen -A hostname -- $ocur ) )

      # apply suffix
      for (( i=0; i &lt; ${#COMPREPLY[@]}; i++ )); do
    COMPREPLY[i]=$user${COMPREPLY[i]}$suffix
      done
  else
      # Just do normal hostname completion
      COMPREPLY=( $( compgen -A hostname -S &quot;$suffix&quot; -- $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='yes'<br />
  [ "$1" = -c ] || [ "$2" = -c ] &amp;&amp; suffix=':'<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=( "${config[@]}" "/etc/ssh/ssh_config" )<br />
  [ -r "${HOME}/.ssh/config" ] &amp;&amp;<br />
    config=( "${config[@]}" "${HOME}/.ssh/config" )<br />
  [ -r "${HOME}/.ssh2/config" ] &amp;&amp;<br />
    config=( "${config[@]}" "${HOME}/.ssh2/config" )</p>
<p>  if [ ${#config[@]} -gt 0 ]; then<br />
      # expand path (if present) to global known hosts file<br />
      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[@]}" ) )<br />
      # expand path (if present) to user known hosts file<br />
      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[@]}" ) )<br />
  fi</p>
<p>  # Global known_hosts files<br />
  [ -r "$global_kh" ] &amp;&amp;<br />
      kh=( "${kh[@]}" "$global_kh" )<br />
  [ -r /etc/ssh/ssh_known_hosts ] &amp;&amp;<br />
      kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts )<br />
  [ -r /etc/ssh/ssh_known_hosts2 ] &amp;&amp;<br />
      kh=( "${kh[@]}" /etc/ssh/ssh_known_hosts2 )<br />
  [ -r /etc/known_hosts ] &amp;&amp;<br />
      kh=( "${kh[@]}" /etc/known_hosts )<br />
  [ -r /etc/known_hosts2 ] &amp;&amp;<br />
      kh=( "${kh[@]}" /etc/known_hosts2 )<br />
  [ -d /etc/ssh2/knownhosts ] &amp;&amp;<br />
      khd=( "${khd[@]}" /etc/ssh2/knownhosts/*pub )</p>
<p>  # User known_hosts files<br />
  [ -r "$user_kh" ] &amp;&amp;<br />
      kh=( "${kh[@]}" "$user_kh" )<br />
  [ -r ~/.ssh/known_hosts ] &amp;&amp;<br />
      kh=( "${kh[@]}" ~/.ssh/known_hosts )<br />
  [ -r ~/.ssh/known_hosts2 ] &amp;&amp;<br />
      kh=( "${kh[@]}" ~/.ssh/known_hosts2 )<br />
  [ -d ~/.ssh2/hostkeys ] &amp;&amp;<br />
      khd=( "${khd[@]}" ~/.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="^$cur.*"<br />
      elif [[ "$cur" == [0-9]* ]]; then<br />
    # Digits followed by no dot - search for digits followed<br />
    # by a dot<br />
    cur="^$cur.*\."<br />
      elif [ -z "$cur" ]; then<br />
    # A blank - search for a dot or an alpha character<br />
    cur="[a-z.]"<br />
      else<br />
    cur="^$cur"<br />
      fi</p>
<p>      if [ ${#kh[@]} -gt 0 ]; then</p>
<p>    # FS needs to look for a comma separated list<br />
    COMPREPLY=( $( awk 'BEGIN {FS=","}<br />
        /^[^|]/ {for (i=1; i/dev/null ) )<br />
      fi<br />
      if [ ${#khd[@]} -gt 0 ]; then<br />
    # Needs to look for files called<br />
    # .../.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 "${khd[@]}" ; do<br />
        if [[ "$i" == *key_22_$curd*.pub ]] &amp;&amp; [ -r "$i" ] ; then<br />
      host=${i/#*key_22_/}<br />
      host=${host/%.pub/}<br />
      COMPREPLY=( "${COMPREPLY[@]}" $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 's/^[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\?['"$'\t '"']\+\([^*?]*\)$/\2/p' "${config[@]}" )<br />
    hosts=$( compgen -W "$host_aliases" -- $ocur )<br />
    COMPREPLY=( "${COMPREPLY[@]}" $hosts )<br />
      fi</p>
<p>      # Now add results of normal hostname completion<br />
      COMPREPLY=( "${COMPREPLY[@]}" $( compgen -A hostname -- $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 "$suffix" -- $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>
