Created
May 7, 2009 06:46
-
-
Save itspriddle/107953 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This function performs host completion based on ssh's known_hosts files, | |
# defaulting to standard host completion if they don't exist. | |
# | |
_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<=2; ++i) { \ | |
gsub(" .*$", "", $i); \ | |
if ($i ~ /'$cur'/) {print $i} \ | |
}}' "${kh[@]}" 2>/dev/null ) ) | |
fi | |
if [ ${#khd[@]} -gt 0 ]; then | |
# Needs to look for files called | |
# .../.ssh2/key_22_<hostname>.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 | |
} | |
complete -F _known_hosts traceroute traceroute6 tracepath tracepath6 \ | |
ping ping6 fping fping6 telnet host nslookup rsh rlogin ftp dig ssh-installkeys mtr | |
# This function expands tildes in pathnames | |
# | |
_expand() | |
{ | |
# FIXME: Why was this here? | |
# [ "$cur" != "${cur%\\}" ] && cur="$cur\\" | |
# expand ~username type directory specifications | |
if [[ "$cur" == \~*/* ]]; then | |
eval cur=$cur | |
elif [[ "$cur" == \~* ]]; then | |
cur=${cur#\~} | |
COMPREPLY=( $( compgen -P '~' -u $cur ) ) | |
return ${#COMPREPLY[@]} | |
fi | |
} | |
# Get the word to complete | |
# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases | |
# where the user is completing in the middle of a word. | |
# (For example, if the line is "ls foobar", | |
# and the cursor is here --------> ^ | |
# it will complete just "foo", not "foobar", which is what the user wants.) | |
_get_cword() | |
{ | |
if [[ "${#COMP_WORDS[COMP_CWORD]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then | |
echo "${COMP_WORDS[COMP_CWORD]}" | |
else | |
local i | |
local cur="$COMP_LINE" | |
local index="$COMP_POINT" | |
for (( i = 0; i <= COMP_CWORD; ++i )); do | |
while [[ "${#cur}" -ge ${#COMP_WORDS[i]} ]] && [[ "${cur:0:${#COMP_WORDS[i]}}" != "${COMP_WORDS[i]}" ]]; do | |
cur="${cur:1}" | |
index="$(( index - 1 ))" | |
done | |
if [[ "$i" -lt "$COMP_CWORD" ]]; then | |
local old_size="${#cur}" | |
cur="${cur#${COMP_WORDS[i]}}" | |
local new_size="${#cur}" | |
index="$(( index - old_size + new_size ))" | |
fi | |
done | |
if [[ "${COMP_WORDS[COMP_CWORD]:0:${#cur}}" != "$cur" ]]; then | |
# We messed up! At least return the whole word so things keep working | |
echo "${COMP_WORDS[COMP_CWORD]}" | |
else | |
echo "${cur:0:$index}" | |
fi | |
fi | |
} | |
# ssh(1) completion | |
# | |
_ssh() | |
{ | |
local cur prev | |
local -a config | |
COMPREPLY=() | |
cur=`_get_cword` | |
prev=${COMP_WORDS[COMP_CWORD-1]} | |
case "$prev" in | |
-*c) | |
COMPREPLY=( $( compgen -W 'blowfish 3des 3des-cbc blowfish-cbc \ | |
arcfour cast128-cbc' -- $cur ) ) | |
;; | |
-*i) | |
_filedir | |
;; | |
-*l) | |
COMPREPLY=( $( compgen -u -- $cur ) ) | |
;; | |
*) | |
_known_hosts -a | |
[ $COMP_CWORD -eq 1 ] || \ | |
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -c -- $cur ) ) | |
esac | |
return 0 | |
} | |
shopt -u hostcomplete && complete -F _ssh ssh slogin sftp xhost autossh | |
_scp() | |
{ | |
local cur userhost path | |
COMPREPLY=() | |
cur=`_get_cword` | |
_expand || return 0 | |
if [[ "$cur" == *:* ]]; then | |
local IFS=$'\t\n' | |
# remove backslash escape from : | |
cur=${cur/\\:/:} | |
userhost=${cur%%?(\\):*} | |
path=${cur#*:} | |
# unescape spaces | |
path=${path//\\\\\\\\ / } | |
if [ -z "$path" ]; then | |
# default to home dir of specified user on remote host | |
path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null) | |
fi | |
# escape spaces; remove executables, aliases, pipes and sockets; | |
# add space at end of file names | |
COMPREPLY=( $( ssh -o 'Batchmode yes' $userhost \ | |
command ls -aF1d "$path*" 2>/dev/null | \ | |
sed -e "s/[][(){}<>\",:;^&!$&=?\`|\\ ']/\\\\\\\\\\\\&/g" \ | |
-e 's/[*@|=]$//g' -e 's/[^\/]$/& /g' ) ) | |
return 0 | |
fi | |
[[ "$cur" == */* ]] || _known_hosts -c -a | |
local IFS=$'\t\n' | |
COMPREPLY=( "${COMPREPLY[@]}" $( command ls -aF1d $cur* \ | |
2>/dev/null | sed \ | |
-e "s/[][(){}<>\",:;^&!$&=?\`|\\ ']/\\\\&/g" \ | |
-e 's/[*@|=]$//g' -e 's/[^\/]$/& /g' ) ) | |
return 0 | |
} | |
complete -F _scp -o nospace scp | |
# Force sudo on gem install | |
gem() { | |
if [[ "$1" == "install" ]]; then | |
sudo command gem $@ | |
else | |
command gem $@ | |
fi | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment