Thoughts on System Administration

24 March, 2008

SSH tab completion

Filed under: Quick Tips, Tools — Tags: — plathrop @ 9:57 am

This is awesome. Put the following into your ~/.bash_profile file:

complete -W "$(echo `cat ~/.ssh/known_hosts | cut -f 1 -d ' ' \
| sed -e s/,.*//g | uniq | grep -v "\["`;)" ssh

Open a new shell and type ssh tab tab. I love tab completion, don’t you?

1 Comment »

  1. From Ubuntu 7.04+’s /etc/bash_completion:


    _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 ] || [ "$2" = -a ] && aliases=’yes’
    [ "$1" = -c ] || [ "$2" = -c ] && suffix=’:’
    [[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@}
    kh=()

    # ssh config files
    [ -r /etc/ssh/ssh_config ] &&
    config=( “${config[@]}” “/etc/ssh/ssh_config” )
    [ -r "${HOME}/.ssh/config" ] &&
    config=( “${config[@]}” “${HOME}/.ssh/config” )
    [ -r "${HOME}/.ssh2/config" ] &&
    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" ] &&
    kh=( “${kh[@]}” “$global_kh” )
    [ -r /etc/ssh/ssh_known_hosts ] &&
    kh=( “${kh[@]}” /etc/ssh/ssh_known_hosts )
    [ -r /etc/ssh/ssh_known_hosts2 ] &&
    kh=( “${kh[@]}” /etc/ssh/ssh_known_hosts2 )
    [ -r /etc/known_hosts ] &&
    kh=( “${kh[@]}” /etc/known_hosts )
    [ -r /etc/known_hosts2 ] &&
    kh=( “${kh[@]}” /etc/known_hosts2 )
    [ -d /etc/ssh2/knownhosts ] &&
    khd=( “${khd[@]}” /etc/ssh2/knownhosts/*pub )

    # User known_hosts files
    [ -r "$user_kh" ] &&
    kh=( “${kh[@]}” “$user_kh” )
    [ -r ~/.ssh/known_hosts ] &&
    kh=( “${kh[@]}” ~/.ssh/known_hosts )
    [ -r ~/.ssh/known_hosts2 ] &&
    kh=( “${kh[@]}” ~/.ssh/known_hosts2 )
    [ -d ~/.ssh2/hostkeys ] &&
    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=”,”}
    /^[^|]/ {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 ]] && [ -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 ] && [ -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 < ${#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
    }

    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

    Comment by AJ — 16 November, 2008 @ 8:46 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment