diff options
Diffstat (limited to 'completions/ssh')
-rw-r--r-- | completions/ssh | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/completions/ssh b/completions/ssh new file mode 100644 index 00000000..cf966ae5 --- /dev/null +++ b/completions/ssh @@ -0,0 +1,428 @@ +# ssh(1) completion + +have ssh && +{ + +_ssh_bindaddress() +{ + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W \ + "$( PATH="$PATH:/sbin" ifconfig -a | \ + sed -ne 's/.*addr:\([^[:space:]]*\).*/\1/p' \ + -ne 's/.*inet[[:space:]]\{1,\}\([^[:space:]]*\).*/\1/p' )" \ + -- "$cur" ) ) +} + +_ssh_ciphers() +{ + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W '3des-cbc aes128-cbc \ + aes192-cbc aes256-cbc aes128-ctr aes192-ctr aes256-ctr arcfour128 \ + arcfour256 arcfour blowfish-cbc cast128-cbc' -- "$cur" ) ) +} + +_ssh_macs() +{ + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W 'hmac-md5 hmac-sha1 \ + umac-64@openssh.com hmac-ripemd160 hmac-sha1-96 hmac-md5-96' \ + -- "$cur" ) ) +} + +_ssh_options() +{ + type compopt &>/dev/null && compopt -o nospace + COMPREPLY=( $( compgen -S = -W 'AddressFamily BatchMode BindAddress \ + ChallengeResponseAuthentication CheckHostIP Cipher Ciphers \ + ClearAllForwardings Compression CompressionLevel ConnectionAttempts \ + ConnectTimeout ControlMaster ControlPath DynamicForward EscapeChar \ + ExitOnForwardFailure ForwardAgent ForwardX11 ForwardX11Trusted \ + GatewayPorts GlobalKnownHostsFile GSSAPIAuthentication \ + GSSAPIDelegateCredentials HashKnownHosts Host HostbasedAuthentication \ + HostKeyAlgorithms HostKeyAlias HostName IdentityFile IdentitiesOnly \ + KbdInteractiveDevices LocalCommand LocalForward LogLevel MACs \ + NoHostAuthenticationForLocalhost NumberOfPasswordPrompts \ + PasswordAuthentication PermitLocalCommand Port \ + PreferredAuthentications Protocol ProxyCommand PubkeyAuthentication \ + RekeyLimit RemoteForward RhostsRSAAuthentication RSAAuthentication \ + SendEnv ServerAliveInterval ServerAliveCountMax SmartcardDevice \ + StrictHostKeyChecking TCPKeepAlive Tunnel TunnelDevice \ + UsePrivilegedPort User UserKnownHostsFile VerifyHostKeyDNS \ + VisualHostKey XAuthLocation' -- "$cur" ) ) +} + +# Complete a ssh suboption (like ForwardAgent=y<tab>) +# Only one parameter: the string to complete including the equal sign. +# Not all suboptions are completed. +# Doesn't handle comma-separated lists. +_ssh_suboption() +{ + # Split into subopt and subval + local prev=${1%%=*} cur=${1#*=} + + case $prev in + BatchMode|ChallengeResponseAuthentication|CheckHostIP|\ + ClearAllForwardings|Compression|ExitOnForwardFailure|ForwardAgent|\ + ForwardX11|ForwardX11Trusted|GatewayPorts|GSSAPIAuthentication|\ + GSSAPIKeyExchange|GSSAPIDelegateCredentials|GSSAPITrustDns|\ + HashKnownHosts|HostbasedAuthentication|IdentitiesOnly|\ + KbdInteractiveAuthentication|KbdInteractiveDevices|\ + NoHostAuthenticationForLocalhost|PasswordAuthentication|\ + PubkeyAuthentication|RhostsRSAAuthentication|RSAAuthentication|\ + StrictHostKeyChecking|TCPKeepAlive|UsePrivilegedPort|\ + VerifyHostKeyDNS|VisualHostKey) + COMPREPLY=( $( compgen -W 'yes no' -- "$cur") ) + ;; + AddressFamily) + COMPREPLY=( $( compgen -W 'any inet inet6' -- "$cur" ) ) + ;; + BindAddress) + _ssh_bindaddress + ;; + Cipher) + COMPREPLY=( $( compgen -W 'blowfish des 3des' -- "$cur" ) ) + ;; + Protocol) + COMPREPLY=( $( compgen -W '1 2 1,2 2,1' -- "$cur" ) ) + ;; + Tunnel) + COMPREPLY=( $( compgen -W 'yes no point-to-point ethernet' \ + -- "$cur" ) ) + ;; + PreferredAuthentications) + COMPREPLY=( $( compgen -W 'gssapi-with-mic host-based \ + publickey keyboard-interactive password' -- "$cur" ) ) + ;; + MACs) + _ssh_macs + ;; + Ciphers) + _ssh_ciphers + ;; + esac + return 0 +} + +# Try to complete -o SubOptions= +# +# Returns 0 if the completion was handled or non-zero otherwise. +_ssh_suboption_check() +{ + # Get prev and cur words without splitting on = + local cureq=`_get_cword :=` preveq=`_get_pword :=` + if [[ $cureq == *=* && $preveq == -o ]]; then + _ssh_suboption $cureq + return $? + fi + return 1 +} + +_ssh() +{ + local cur prev configfile + local -a config + + COMPREPLY=() + _get_comp_words_by_ref -n : cur prev + #cur=`_get_cword :` + #prev=`_get_pword` + + _ssh_suboption_check && return 0 + + case $prev in + -F|-i|-S) + _filedir + return 0 + ;; + -c) + _ssh_ciphers + return 0 + ;; + -m) + _ssh_macs + return 0 + ;; + -l) + COMPREPLY=( $( compgen -u -- "$cur" ) ) + return 0 + ;; + -o) + _ssh_options + return 0 + ;; + -w) + _available_interfaces + return 0 + ;; + -b) + _ssh_bindaddress + return 0 + ;; + esac + + if [[ "$cur" == -F* ]]; then + cur=${cur#-F} + _filedir + # Prefix completions with '-F' + COMPREPLY=( "${COMPREPLY[@]/#/-F}" ) + cur=-F$cur # Restore cur + elif [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W '-1 -2 -4 -6 -A -a -C -f -g -K -k -M \ + -N -n -q -s -T -t -V -v -X -v -Y -y -b -b -c -D -e -F \ + -i -L -l -m -O -o -p -R -S -w' -- "$cur" ) ) + else + # Search COMP_WORDS for '-F configfile' or '-Fconfigfile' argument + set -- "${COMP_WORDS[@]}" + while [ $# -gt 0 ]; do + if [ "${1:0:2}" = -F ]; then + if [ ${#1} -gt 2 ]; then + configfile="$(dequote "${1:2}")" + else + shift + [ "$1" ] && configfile="$(dequote "$1")" + fi + break + fi + shift + done + _known_hosts_real -a -F "$configfile" "$cur" + if [ $COMP_CWORD -ne 1 ]; then + _compopt_o_filenames + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -c -- "$cur" ) ) + fi + fi + + return 0 +} +shopt -u hostcomplete && complete -F _ssh ssh slogin autossh + +# sftp(1) completion +# +_sftp() +{ + local cur prev configfile + + COMPREPLY=() + _get_comp_words_by_ref cur prev + + _ssh_suboption_check && return 0 + + case $prev in + -b|-F|-P) + _filedir + return 0 + ;; + -o) + _ssh_options + return 0 + ;; + esac + + if [[ "$cur" == -F* ]]; then + cur=${cur#-F} + _filedir + # Prefix completions with '-F' + COMPREPLY=( "${COMPREPLY[@]/#/-F}" ) + cur=-F$cur # Restore cur + elif [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W '-1 -C -v -B -b -F -o -P -R -S -s' \ + -- "$cur" ) ) + else + # Search COMP_WORDS for '-F configfile' argument + set -- "${COMP_WORDS[@]}" + while [ $# -gt 0 ]; do + if [ "${1:0:2}" = -F ]; then + if [ ${#1} -gt 2 ]; then + configfile="$(dequote "${1:2}")" + else + shift + [ "$1" ] && configfile="$(dequote "$1")" + fi + break + fi + shift + done + _known_hosts_real -a -F "$configfile" "$cur" + fi + + return 0 +} +shopt -u hostcomplete && complete -F _sftp sftp + +# things we want to backslash escape in scp paths +_scp_path_esc='[][(){}<>",:;^&!$=?`|\\'"'"'[:space:]]' + +# Complete remote files with ssh. If the first arg is -d, complete on dirs +# only. Returns paths escaped with three backslashes. +_scp_remote_files() +{ + local IFS=$'\n' + + # remove backslash escape from the first colon + cur=${cur/\\:/:} + + local userhost=${cur%%?(\\):*} + local path=${cur#*:} + + # unescape (3 backslashes to 1 for chars we escaped) + path=$( sed -e 's/\\\\\\\('$_scp_path_esc'\)/\\\1/g' <<<"$path" ) + + # default to home dir of specified user on remote host + if [ -z "$path" ]; then + path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null) + fi + + local files + if [ "$1" = -d ] ; then + # escape problematic characters; remove non-dirs + files=$( ssh -o 'Batchmode yes' $userhost \ + command ls -aF1d "$path*" 2>/dev/null | \ + sed -e 's/'$_scp_path_esc'/\\\\\\&/g' -e '/[^\/]$/d' ) + else + # escape problematic characters; remove executables, aliases, pipes + # and sockets; add space at end of file names + files=$( ssh -o 'Batchmode yes' $userhost \ + command ls -aF1d "$path*" 2>/dev/null | \ + sed -e 's/'$_scp_path_esc'/\\\\\\&/g' -e 's/[*@|=]$//g' \ + -e 's/[^\/]$/& /g' ) + fi + COMPREPLY=( "${COMPREPLY[@]}" $files ) +} + +# This approach is used instead of _filedir to get a space appended +# after local file/dir completions, and -o nospace retained for others. +# If first arg is -d, complete on directory names only. The next arg is +# an optional prefix to add to returned completions. +_scp_local_files() +{ + local IFS=$'\n' + + local dirsonly=false + if [ "$1" = -d ]; then + dirsonly=true + shift + fi + + if $dirsonly ; then + COMPREPLY=( "${COMPREPLY[@]}" $( command ls -aF1d $cur* 2>/dev/null | \ + sed -e "s/$_scp_path_esc/\\\\&/g" -e '/[^\/]$/d' -e "s/^/$1/") ) + else + COMPREPLY=( "${COMPREPLY[@]}" $( command ls -aF1d $cur* 2>/dev/null | \ + sed -e "s/$_scp_path_esc/\\\\&/g" -e 's/[*@|=]$//g' \ + -e 's/[^\/]$/& /g' -e "s/^/$1/") ) + fi +} + +# scp(1) completion +# +_scp() +{ + local configfile cur prev prefix + + COMPREPLY=() + _get_comp_words_by_ref -n : cur prev + + _ssh_suboption_check && { + COMPREPLY=( "${COMPREPLY[@]/%/ }" ) + return 0 + } + + case $prev in + -l|-P) + return 0 + ;; + -F|-i|-S) + _filedir + type compopt &>/dev/null && compopt +o nospace + return 0 + ;; + -c) + _ssh_ciphers + COMPREPLY=( "${COMPREPLY[@]/%/ }" ) + return 0 + ;; + -o) + _ssh_options + return 0 + ;; + esac + + _expand || return 0 + + if [[ "$cur" == *:* ]]; then + _scp_remote_files + return 0 + fi + + if [[ "$cur" == -F* ]]; then + cur=${cur#-F} + prefix=-F + else + # Search COMP_WORDS for '-F configfile' or '-Fconfigfile' argument + set -- "${COMP_WORDS[@]}" + while [ $# -gt 0 ]; do + if [ "${1:0:2}" = -F ]; then + if [ ${#1} -gt 2 ]; then + configfile="$(dequote "${1:2}")" + else + shift + [ "$1" ] && configfile="$(dequote "$1")" + fi + break + fi + shift + done + + case $cur in + -*) + COMPREPLY=( $( compgen -W '-1 -2 -4 -6 -B -C -c -F -i -l -o \ + -P -p -q -r -S -v' -- "$cur" ) ) + COMPREPLY=( "${COMPREPLY[@]/%/ }" ) + return 0 + ;; + */*) + # pass through + ;; + *) + _known_hosts_real -c -a -F "$configfile" "$cur" + ;; + esac + fi + + _scp_local_files "$prefix" + + return 0 +} +complete -F _scp -o nospace scp + +# ssh-copy-id(1) completion +# +_ssh_copy_id() +{ + local cur prev + + COMPREPLY=() + _get_comp_words_by_ref cur prev + + case $prev in + -i) + _filedir + return 0 + ;; + esac + + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W '-i' -- "$cur" ) ) + else + _known_hosts_real -a "$cur" + fi + + return 0 +} +complete -F _ssh_copy_id ssh-copy-id +} + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh |