[Bash-completion-devel] Bug#504141: bash-completion: Improved known_hosts completion with -F support, hosts indented or comment-trailed

Freddy Vulto fvulto at gmail.com
Fri Oct 31 23:36:46 UTC 2008


Package: bash-completion
Version: 20080705
Severity: normal

Attached are improvements to _known_hosts, ssh, scp and sftp:
- Added support for `-F configfile' to _known_hosts.  I've done this especially
  to make it easier to configure an ssh testsuite when writing automated tests.
- Allow `Host(Name)' in ssh config file to be indented
- Allow `Host(Name)' in ssh config file to have trailing comment.  Note that
  SSH allows a comment after `Host' but not after `HostName'.  In the latter
  case you'll get an error message when trying to scp/ssh/sftp:
  
     garbage at end of line; "#".


Regards,

Freddy Vulto

-- System Information:
Debian Release: 4.0
  APT prefers stable
  APT policy: (500, 'stable')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.18-6-686
Locale: LANG=en_US, LC_CTYPE=en_US (charmap=ISO-8859-1)
-------------- next part --------------
=== modified file 'bash_completion'
--- bash_completion	2008-10-10 19:01:59 +0000
+++ bash_completion	2008-10-31 22:47:29 +0000
@@ -2503,28 +2511,42 @@
 
 # This function performs host completion based on ssh's known_hosts files,
 # defaulting to standard host completion if they don't exist.
-#
+# Arguments:  -a             Use aliases
+#             -c             Use `:' suffix
+#             -F configfile  Use `configfile' for configuration settings
 _known_hosts()
 {
-       local cur curd ocur user suffix aliases global_kh user_kh hosts i host
+       local configfile 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=':'
+	local OPTIND=1
+	while getopts "acF:" flag "$@"; do 
+	    case $flag in
+		a) aliases='yes' ;;
+		c) suffix=':' ;;
+		F) configfile="$OPTARG" ;;
+	    esac
+	done
+
 	[[ $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 [ -n "$configfile" ]; then
+	    [ -r "$configfile" ] && 
+		config=( "${config[@]}" "$configfile" )
+	else
+	    [ -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" )
+	fi
 
 	if [ ${#config[@]} -gt 0 ]; then
 	    # expand path (if present) to global known hosts file
@@ -2536,29 +2558,33 @@
 	# 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 )
+	if [ -z "$configfile" ]; then
+	    [ -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 )
+	fi
 
 	# 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 [ -z "$configfile" ]; then
+	    [ -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 )
+	fi
 
 	# If we have known_hosts files to use
-	if [ ${#kh[@]} -gt 0 -o ${#khd[@]} -gt 0 ]; then
+	if [ ${#kh[@]} -gt 0 -o ${#khd[@]} -gt 0 -o -n "$configfile" ]; then
 	    # Escape slashes and dots in paths for awk
 	    cur=${cur//\//\\\/}
 	    cur=${cur//\./\\\.}
@@ -2602,7 +2628,7 @@
 	    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[@]}" )
+	    local host_aliases=$( sed -ne 's/^[ \t]*[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\?['"$'\t '"']\+\([^#*?]*\)\(#.*\)\?$/\2/p' "${config[@]}" )
 	    hosts=$( compgen -W "$host_aliases" -- $ocur )
 		COMPREPLY=( "${COMPREPLY[@]}" $hosts )
 	    fi
@@ -2614,7 +2640,7 @@
 	    for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
 		COMPREPLY[i]=$user${COMPREPLY[i]}$suffix
 	    done
-	else
+	elif [ -z "$configfile" ]; then
 	    # Just do normal hostname completion
 	    COMPREPLY=( $( compgen -A hostname -S "$suffix" -- $cur ) )
 	fi

=== modified file 'contrib/ssh'
--- contrib/ssh	2008-09-27 10:58:42 +0000
+++ contrib/ssh	2008-10-31 22:58:15 +0000
@@ -3,7 +3,7 @@
 have ssh && {
 _ssh()
 {
-	local cur prev
+	local cur optconfigfile prev
 	local -a config
 
 	COMPREPLY=()
@@ -11,6 +11,9 @@
 	prev=${COMP_WORDS[COMP_CWORD-1]}
 
 	case "$prev" in
+	-F)
+	    _filedir
+	    ;;
 	-*c)
 	    COMPREPLY=( $( compgen -W 'blowfish 3des 3des-cbc blowfish-cbc \
 			   arcfour cast128-cbc' -- $cur ) )
@@ -22,9 +25,24 @@
 	    COMPREPLY=( $( compgen -u -- $cur ) )
 	    ;;
 	*)
-	    _known_hosts -a
-
-	    [ $COMP_CWORD -eq 1 ] || \
+	    # 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
+			optconfigfile="$i"
+		    else
+			shift
+			optconfigfile="-F$1"
+		    fi
+		    break
+		fi
+		shift
+	    done
+
+	    _known_hosts -a $optconfigfile
+
+	    [ $COMP_CWORD -eq 1 -o -n "$optconfigfile" ] || \
 		COMPREPLY=( "${COMPREPLY[@]}" $( compgen -c -- $cur ) )
 	esac
 
@@ -36,7 +54,7 @@
 #
 _scp()
 {
-	local cur userhost path
+	local cur optconfigfile userhost path
 
 	COMPREPLY=()
 	cur=`_get_cword ":"`
@@ -63,8 +81,23 @@
 				   -e 's/[*@|=]$//g' -e 's/[^\/]$/& /g' ) )
 		return 0
 	fi
+ 
+	# 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
+		    optconfigfile="$i"
+		else
+		    shift
+		    optconfigfile="-F$1"
+		fi
+		break
+	    fi
+	    shift
+	done
 
-	[[ "$cur" == */* ]] || _known_hosts -c -a
+	[[ "$cur" == */* ]] || _known_hosts -c -a $optconfigfile
 		local IFS=$'\t\n'
 		COMPREPLY=( "${COMPREPLY[@]}" $( command ls -aF1d $cur* \
 			    2>/dev/null | sed \



More information about the Bash-completion-devel mailing list