1373 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			1373 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| ##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| ## Fonctions pour l'autocomplétion bash, si le package bash-completion n'est pas installé
 | |
| ##@cooked nocomments
 | |
| ##@require base
 | |
| uprovide bash_completion
 | |
| 
 | |
| if [ -z "$BASH_COMPLETION" ]; then
 | |
|     BASH_COMPLETION=1
 | |
|     shopt -s extglob progcomp
 | |
| 
 | |
| ##--start[RIPPED from /etc/bash_completion-----------------------------------]--
 | |
| UNAME=$( uname -s )
 | |
| # strip OS type and version under Cygwin (e.g. CYGWIN_NT-5.1 => Cygwin)
 | |
| UNAME=${UNAME/CYGWIN_*/Cygwin}
 | |
| 
 | |
| case ${UNAME} in
 | |
|     Linux|GNU|GNU/*) USERLAND=GNU ;;
 | |
|     *) USERLAND=${UNAME} ;;
 | |
| esac
 | |
| ##--end[RIPPED from /etc/bash_completion-------------------------------------]--
 | |
| 
 | |
| ##--start[RIPPED from /etc/bash_completion-----------------------------------]--
 | |
| # start of section containing completion functions called by other functions
 | |
| 
 | |
| # This function checks whether we have a given program on the system.
 | |
| # No need for bulky functions in memory if we don't.
 | |
| #
 | |
| have()
 | |
| {
 | |
|     unset -v have
 | |
|     # Completions for system administrator commands are installed as well in
 | |
|     # case completion is attempted via `sudo command ...'.
 | |
|     PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin type $1 &>/dev/null &&
 | |
|     have="yes"
 | |
| }
 | |
| 
 | |
| # This function checks whether a given readline variable
 | |
| # is `on'.
 | |
| #
 | |
| _rl_enabled()
 | |
| {
 | |
|     [[ "$( bind -v )" = *$1+([[:space:]])on* ]]
 | |
| }
 | |
| 
 | |
| # This function shell-quotes the argument
 | |
| quote()
 | |
| {
 | |
|     echo \'${1//\'/\'\\\'\'}\' #'# Help vim syntax highlighting
 | |
| }
 | |
| 
 | |
| # @see _quote_readline_by_ref()
 | |
| quote_readline()
 | |
| {
 | |
|     local quoted
 | |
|     _quote_readline_by_ref "$1" ret
 | |
|     printf %s "$ret"
 | |
| } # quote_readline()
 | |
| 
 | |
| 
 | |
| # This function shell-dequotes the argument
 | |
| dequote()
 | |
| {
 | |
|     eval echo "$1" 2> /dev/null
 | |
| }
 | |
| 
 | |
| 
 | |
| # Assign variable one scope above the caller
 | |
| # Usage: local "$1" && _upvar $1 "value(s)"
 | |
| # Param: $1  Variable name to assign value to
 | |
| # Param: $*  Value(s) to assign.  If multiple values, an array is
 | |
| #            assigned, otherwise a single value is assigned.
 | |
| # NOTE: For assigning multiple variables, use '_upvars'.  Do NOT
 | |
| #       use multiple '_upvar' calls, since one '_upvar' call might
 | |
| #       reassign a variable to be used by another '_upvar' call.
 | |
| # See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
 | |
| _upvar() {
 | |
|     if unset -v "$1"; then           # Unset & validate varname
 | |
|         if (( $# == 2 )); then
 | |
|             eval $1=\"\$2\"          # Return single value
 | |
|         else
 | |
|             eval $1=\(\"\${@:2}\"\)  # Return array
 | |
|         fi
 | |
|     fi
 | |
| }
 | |
| 
 | |
| 
 | |
| # Assign variables one scope above the caller
 | |
| # Usage: local varname [varname ...] && 
 | |
| #        _upvars [-v varname value] | [-aN varname [value ...]] ...
 | |
| # Available OPTIONS:
 | |
| #     -aN  Assign next N values to varname as array
 | |
| #     -v   Assign single value to varname
 | |
| # Return: 1 if error occurs
 | |
| # See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
 | |
| _upvars() {
 | |
|     if ! (( $# )); then
 | |
|         echo "${FUNCNAME[0]}: usage: ${FUNCNAME[0]} [-v varname"\
 | |
|             "value] | [-aN varname [value ...]] ..." 1>&2
 | |
|         return 2
 | |
|     fi
 | |
|     while (( $# )); do
 | |
|         case $1 in
 | |
|             -a*)
 | |
|                 # Error checking
 | |
|                 [[ ${1#-a} ]] || { echo "bash: ${FUNCNAME[0]}: \`$1': missing"\
 | |
|                     "number specifier" 1>&2; return 1; }
 | |
|                 printf %d "${1#-a}" &> /dev/null || { echo "bash:"\
 | |
|                     "${FUNCNAME[0]}: \`$1': invalid number specifier" 1>&2
 | |
|                     return 1; }
 | |
|                 # Assign array of -aN elements
 | |
|                 [[ "$2" ]] && unset -v "$2" && eval $2=\(\"\${@:3:${1#-a}}\"\) && 
 | |
|                 shift $((${1#-a} + 2)) || { echo "bash: ${FUNCNAME[0]}:"\
 | |
|                     "\`$1${2+ }$2': missing argument(s)" 1>&2; return 1; }
 | |
|                 ;;
 | |
|             -v)
 | |
|                 # Assign single value
 | |
|                 [[ "$2" ]] && unset -v "$2" && eval $2=\"\$3\" &&
 | |
|                 shift 3 || { echo "bash: ${FUNCNAME[0]}: $1: missing"\
 | |
|                 "argument(s)" 1>&2; return 1; }
 | |
|                 ;;
 | |
|             *)
 | |
|                 echo "bash: ${FUNCNAME[0]}: $1: invalid option" 1>&2
 | |
|                 return 1 ;;
 | |
|         esac
 | |
|     done
 | |
| }
 | |
| 
 | |
| 
 | |
| # Reassemble command line words, excluding specified characters from the
 | |
| # list of word completion separators (COMP_WORDBREAKS).
 | |
| # @param $1 chars  Characters out of $COMP_WORDBREAKS which should
 | |
| #     NOT be considered word breaks. This is useful for things like scp where
 | |
| #     we want to return host:path and not only path, so we would pass the
 | |
| #     colon (:) as $1 here.
 | |
| # @param $2 words  Name of variable to return words to
 | |
| # @param $3 cword  Name of variable to return cword to
 | |
| #
 | |
| __reassemble_comp_words_by_ref() {
 | |
|     local exclude i j ref
 | |
|     # Exclude word separator characters?
 | |
|     if [[ $1 ]]; then
 | |
|         # Yes, exclude word separator characters;
 | |
|         # Exclude only those characters, which were really included
 | |
|         exclude="${1//[^$COMP_WORDBREAKS]}"
 | |
|     fi
 | |
|         
 | |
|     # Default to cword unchanged
 | |
|     eval $3=$COMP_CWORD
 | |
|     # Are characters excluded which were former included?
 | |
|     if [[ $exclude ]]; then
 | |
|         # Yes, list of word completion separators has shrunk;
 | |
|         # Re-assemble words to complete
 | |
|         for (( i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
 | |
|             # Is current word not word 0 (the command itself) and is word not
 | |
|             # empty and is word made up of just word separator characters to be
 | |
|             # excluded?
 | |
|             while [[ $i -gt 0 && ${COMP_WORDS[$i]} && 
 | |
|                 ${COMP_WORDS[$i]//[^$exclude]} == ${COMP_WORDS[$i]} 
 | |
|             ]]; do
 | |
|                 [ $j -ge 2 ] && ((j--))
 | |
|                 # Append word separator to current word
 | |
|                 ref="$2[$j]"
 | |
|                 eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
 | |
|                 # Indicate new cword
 | |
|                 [ $i = $COMP_CWORD ] && eval $3=$j
 | |
|                 # Indicate next word if available, else end *both* while and for loop
 | |
|                 (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2
 | |
|             done
 | |
|             # Append word to current word
 | |
|             ref="$2[$j]"
 | |
|             eval $2[$j]=\${!ref}\${COMP_WORDS[i]}
 | |
|             # Indicate new cword
 | |
|             [ $i = $COMP_CWORD ] && [[ ${COMP_WORDS[i]} ]] && eval $3=$j
 | |
|         done
 | |
|     else
 | |
|         # No, list of word completions separators hasn't changed;
 | |
|         eval $2=\( \"\${COMP_WORDS[@]}\" \)
 | |
|     fi
 | |
| } # __reassemble_comp_words_by_ref()
 | |
| 
 | |
| 
 | |
| # @param $1 exclude  Characters out of $COMP_WORDBREAKS which should NOT be
 | |
| #     considered word breaks. This is useful for things like scp where
 | |
| #     we want to return host:path and not only path, so we would pass the
 | |
| #     colon (:) as $1 in this case.  Bash-3 doesn't do word splitting, so this
 | |
| #     ensures we get the same word on both bash-3 and bash-4.
 | |
| # @param $2 words  Name of variable to return words to
 | |
| # @param $3 cword  Name of variable to return cword to
 | |
| # @param $4 cur  Name of variable to return current word to complete to
 | |
| # @see ___get_cword_at_cursor_by_ref()
 | |
| __get_cword_at_cursor_by_ref() {
 | |
|     local cword words=()
 | |
|     __reassemble_comp_words_by_ref "$1" words cword
 | |
| 
 | |
|     local i cur2
 | |
|     local cur="$COMP_LINE"
 | |
|     local index="$COMP_POINT"
 | |
|     for (( i = 0; i <= cword; ++i )); do
 | |
|         while [[
 | |
|             # Current word fits in $cur?
 | |
|             "${#cur}" -ge ${#words[i]} &&
 | |
|             # $cur doesn't match cword?
 | |
|             "${cur:0:${#words[i]}}" != "${words[i]}"
 | |
|         ]]; do
 | |
|             # Strip first character
 | |
|             cur="${cur:1}"
 | |
|             # Decrease cursor position
 | |
|             ((index--))
 | |
|         done
 | |
| 
 | |
|         # Does found word matches cword?
 | |
|         if [[ "$i" -lt "$cword" ]]; then
 | |
|             # No, cword lies further;
 | |
|             local old_size="${#cur}"
 | |
|             cur="${cur#${words[i]}}"
 | |
|             local new_size="${#cur}"
 | |
|             index=$(( index - old_size + new_size ))
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then
 | |
|         # We messed up. At least return the whole word so things keep working
 | |
|         cur2=${words[cword]}
 | |
|     else
 | |
|         cur2=${cur:0:$index}
 | |
|     fi
 | |
| 
 | |
|     local "$2" "$3" "$4" && 
 | |
|         _upvars -a${#words[@]} $2 "${words[@]}" -v $3 "$cword" -v $4 "$cur2"
 | |
| }
 | |
| 
 | |
| 
 | |
| # Get the word to complete and optional previous words.
 | |
| # 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 -------->   ^
 | |
| # Also one is able to cross over possible wordbreak characters.
 | |
| # Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES]
 | |
| # Available VARNAMES:
 | |
| #     cur         Return cur via $cur
 | |
| #     prev        Return prev via $prev
 | |
| #     words       Return words via $words
 | |
| #     cword       Return cword via $cword
 | |
| #
 | |
| # Available OPTIONS:
 | |
| #     -n EXCLUDE  Characters out of $COMP_WORDBREAKS which should NOT be 
 | |
| #                 considered word breaks. This is useful for things like scp
 | |
| #                 where we want to return host:path and not only path, so we
 | |
| #                 would pass the colon (:) as -n option in this case.  Bash-3
 | |
| #                 doesn't do word splitting, so this ensures we get the same
 | |
| #                 word on both bash-3 and bash-4.
 | |
| #     -c VARNAME  Return cur via $VARNAME
 | |
| #     -p VARNAME  Return prev via $VARNAME
 | |
| #     -w VARNAME  Return words via $VARNAME
 | |
| #     -i VARNAME  Return cword via $VARNAME
 | |
| #
 | |
| # Example usage:
 | |
| #
 | |
| #    $ _get_comp_words_by_ref -n : cur prev
 | |
| #
 | |
| _get_comp_words_by_ref()
 | |
| {
 | |
|     local exclude flag i OPTIND=1
 | |
|     local cur cword words=()
 | |
|     local upargs=() upvars=() vcur vcword vprev vwords
 | |
| 
 | |
|     while getopts "c:i:n:p:w:" flag "$@"; do
 | |
|         case $flag in
 | |
|             c) vcur=$OPTARG ;;
 | |
|             i) vcword=$OPTARG ;;
 | |
|             n) exclude=$OPTARG ;;
 | |
|             p) vprev=$OPTARG ;;
 | |
|             w) vwords=$OPTARG ;;
 | |
|         esac
 | |
|     done
 | |
|     while [[ $# -ge $OPTIND ]]; do 
 | |
|         case ${!OPTIND} in
 | |
|             cur)   vcur=cur ;;
 | |
|             prev)  vprev=prev ;;
 | |
|             cword) vcword=cword ;;
 | |
|             words) vwords=words ;;
 | |
|             *) echo "bash: $FUNCNAME(): \`${!OPTIND}': unknown argument" \
 | |
|                 1>&2; return 1
 | |
|         esac
 | |
|         let "OPTIND += 1"
 | |
|     done
 | |
| 
 | |
|     __get_cword_at_cursor_by_ref "$exclude" words cword cur
 | |
| 
 | |
|     [[ $vcur   ]] && { upvars+=("$vcur"  ); upargs+=(-v $vcur   "$cur"  ); }
 | |
|     [[ $vcword ]] && { upvars+=("$vcword"); upargs+=(-v $vcword "$cword"); }
 | |
|     [[ $vprev  ]] && { upvars+=("$vprev" ); upargs+=(-v $vprev 
 | |
|         "${words[cword - 1]}"); }
 | |
|     [[ $vwords ]] && { upvars+=("$vwords"); upargs+=(-a${#words[@]} $vwords
 | |
|         "${words[@]}"); }
 | |
| 
 | |
|     (( ${#upvars[@]} )) && local "${upvars[@]}" && _upvars "${upargs[@]}"
 | |
| }
 | |
| 
 | |
| 
 | |
| # 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 -------->   ^
 | |
| # @param $1 string  Characters out of $COMP_WORDBREAKS which should NOT be
 | |
| #     considered word breaks. This is useful for things like scp where
 | |
| #     we want to return host:path and not only path, so we would pass the
 | |
| #     colon (:) as $1 in this case.  Bash-3 doesn't do word splitting, so this
 | |
| #     ensures we get the same word on both bash-3 and bash-4.
 | |
| # @param $2 integer  Index number of word to return, negatively offset to the
 | |
| #     current word (default is 0, previous is 1), respecting the exclusions
 | |
| #     given at $1.  For example, `_get_cword "=:" 1' returns the word left of
 | |
| #     the current word, respecting the exclusions "=:".
 | |
| # @deprecated  Use `_get_comp_words_by_ref cur' instead
 | |
| # @see _get_comp_words_by_ref()
 | |
| _get_cword()
 | |
| {
 | |
|     local LC_CTYPE=C
 | |
|     local cword words
 | |
|     __reassemble_comp_words_by_ref "$1" words cword
 | |
| 
 | |
|     # return previous word offset by $2
 | |
|     if [[ ${2//[^0-9]/} ]]; then
 | |
|         printf "%s" "${words[cword-$2]}"
 | |
|     elif [[ "${#words[cword]}" -eq 0 ]] || [[ "$COMP_POINT" == "${#COMP_LINE}" ]]; then
 | |
|         printf "%s" "${words[cword]}"
 | |
|     else
 | |
|         local i
 | |
|         local cur="$COMP_LINE"
 | |
|         local index="$COMP_POINT"
 | |
|         for (( i = 0; i <= cword; ++i )); do
 | |
|             while [[
 | |
|                 # Current word fits in $cur?
 | |
|                 "${#cur}" -ge ${#words[i]} &&
 | |
|                 # $cur doesn't match cword?
 | |
|                 "${cur:0:${#words[i]}}" != "${words[i]}"
 | |
|             ]]; do
 | |
|                 # Strip first character
 | |
|                 cur="${cur:1}"
 | |
|                 # Decrease cursor position
 | |
|                 ((index--))
 | |
|             done
 | |
| 
 | |
|             # Does found word matches cword?
 | |
|             if [[ "$i" -lt "$cword" ]]; then
 | |
|                 # No, cword lies further;
 | |
|                 local old_size="${#cur}"
 | |
|                 cur="${cur#${words[i]}}"
 | |
|                 local new_size="${#cur}"
 | |
|                 index=$(( index - old_size + new_size ))
 | |
|             fi
 | |
|         done
 | |
| 
 | |
|         if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then
 | |
|             # We messed up! At least return the whole word so things
 | |
|             # keep working
 | |
|             printf "%s" "${words[cword]}"
 | |
|         else
 | |
|             printf "%s" "${cur:0:$index}"
 | |
|         fi
 | |
|     fi
 | |
| } # _get_cword()
 | |
| 
 | |
| 
 | |
| # Get word previous to the current word.
 | |
| # This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4
 | |
| # will properly return the previous word with respect to any given exclusions to
 | |
| # COMP_WORDBREAKS.
 | |
| # @deprecated  Use `_get_comp_words_by_ref cur prev' instead
 | |
| # @see _get_comp_words_by_ref()
 | |
| #
 | |
| _get_pword() 
 | |
| {
 | |
|     if [ $COMP_CWORD -ge 1 ]; then
 | |
|         _get_cword "${@:-}" 1;
 | |
|     fi
 | |
| }
 | |
| 
 | |
| 
 | |
| # If the word-to-complete contains a colon (:), left-trim COMPREPLY items with
 | |
| # word-to-complete.
 | |
| # On bash-3, and bash-4 with a colon in COMP_WORDBREAKS, words containing
 | |
| # colons are always completed as entire words if the word to complete contains
 | |
| # a colon.  This function fixes this, by removing the colon-containing-prefix
 | |
| # from COMPREPLY items.
 | |
| # The preferred solution is to remove the colon (:) from COMP_WORDBREAKS in
 | |
| # your .bashrc:
 | |
| #
 | |
| #    # Remove colon (:) from list of word completion separators
 | |
| #    COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
 | |
| #
 | |
| # See also: Bash FAQ - E13) Why does filename completion misbehave if a colon
 | |
| # appears in the filename? - http://tiswww.case.edu/php/chet/bash/FAQ
 | |
| # @param $1 current word to complete (cur)
 | |
| # @modifies global array $COMPREPLY
 | |
| #
 | |
| __ltrim_colon_completions() {
 | |
|     # If word-to-complete contains a colon,
 | |
|     # and bash-version < 4,
 | |
|     # or bash-version >= 4 and COMP_WORDBREAKS contains a colon
 | |
|     if [[
 | |
|         "$1" == *:* && (
 | |
|             ${BASH_VERSINFO[0]} -lt 4 || 
 | |
|             (${BASH_VERSINFO[0]} -ge 4 && "$COMP_WORDBREAKS" == *:*) 
 | |
|         )
 | |
|     ]]; then
 | |
|         # Remove colon-word prefix from COMPREPLY items
 | |
|         local colon_word=${1%${1##*:}}
 | |
|         local i=${#COMPREPLY[*]}
 | |
|         while [ $((--i)) -ge 0 ]; do
 | |
|             COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
 | |
|         done
 | |
|     fi
 | |
| } # __ltrim_colon_completions()
 | |
| 
 | |
| 
 | |
| # This function quotes the argument in a way so that readline dequoting
 | |
| # results in the original argument.  This is necessary for at least
 | |
| # `compgen' which requires its arguments quoted/escaped:
 | |
| #
 | |
| #     $ ls "a'b/"
 | |
| #     c
 | |
| #     $ compgen -f "a'b/"       # Wrong, doesn't return output
 | |
| #     $ compgen -f "a\'b/"      # Good (bash-4)
 | |
| #     a\'b/c
 | |
| #     $ compgen -f "a\\\\\'b/"  # Good (bash-3)
 | |
| #     a\'b/c
 | |
| #
 | |
| # See also: http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html
 | |
| # @param $1  Argument to quote
 | |
| # @param $2  Name of variable to return result to
 | |
| _quote_readline_by_ref()
 | |
| {
 | |
|     if [[ ${1:0:1} == "'" ]]; then
 | |
|         # Quote word, leaving out first character
 | |
|         printf -v $2 %q "${1:1}"
 | |
|         if [[ ${BASH_VERSINFO[0]} -le 3 ]]; then
 | |
|             # Double-quote word on bash-3
 | |
|             printf -v $2 %q ${!2}
 | |
|         fi
 | |
|     elif [[ ${BASH_VERSINFO[0]} -le 3 && ${1:0:1} == '"' ]]; then
 | |
|         printf -v $2 %q "${1:1}"
 | |
|     else
 | |
|         printf -v $2 %q "$1"
 | |
|     fi
 | |
| 
 | |
|     # If result becomes quoted like this: $'string', re-evaluate in order to
 | |
|     # drop the additional quoting.  See also: http://www.mail-archive.com/
 | |
|     # bash-completion-devel@lists.alioth.debian.org/msg01942.html
 | |
|     [[ ${!2:0:1} == '$' ]] && eval $2=${!2}
 | |
| } # _quote_readline_by_ref()
 | |
| 
 | |
| 
 | |
| # This function performs file and directory completion. It's better than
 | |
| # simply using 'compgen -f', because it honours spaces in filenames.
 | |
| # @param $1  If `-d', complete only on directories.  Otherwise filter/pick only
 | |
| #            completions with `.$1' as file extension.
 | |
| #
 | |
| _filedir()
 | |
| {
 | |
|     local i IFS=$'\t\n' xspec
 | |
| 
 | |
|     __expand_tilde_by_ref cur
 | |
| 
 | |
|     local -a toks
 | |
|     local quoted tmp
 | |
| 
 | |
|     _quote_readline_by_ref "$cur" quoted
 | |
|     toks=( ${toks[@]-} $(
 | |
|         compgen -d -- "$quoted" | {
 | |
|             while read -r tmp; do
 | |
|                 # TODO: I have removed a "[ -n $tmp ] &&" before 'printf ..',
 | |
|                 #       and everything works again. If this bug suddenly
 | |
|                 #       appears again (i.e. "cd /b<TAB>" becomes "cd /"),
 | |
|                 #       remember to check for other similar conditionals (here
 | |
|                 #       and _filedir_xspec()). --David
 | |
|                 printf '%s\n' $tmp
 | |
|             done
 | |
|         }
 | |
|     ))
 | |
| 
 | |
|     # On bash-3, special characters need to be escaped extra.  This is
 | |
|     # unless the first character is a single quote (').  If the single
 | |
|     # quote appears further down the string, bash default completion also
 | |
|     # fails, e.g.:
 | |
|     #
 | |
|     #     $ ls 'a&b/'
 | |
|     #     f
 | |
|     #     $ foo 'a&b/<TAB>  # Becomes: foo 'a&b/f'
 | |
|     #     $ foo a'&b/<TAB>  # Nothing happens
 | |
|     #
 | |
|     if [[ "$1" != -d ]]; then
 | |
|         xspec=${1:+"!*.$1"}
 | |
|         if [[ ${cur:0:1} == "'" && ${BASH_VERSINFO[0]} -ge 4 ]]; then
 | |
|             toks=( ${toks[@]-} $(
 | |
|                 eval compgen -f -X \"\$xspec\" -- $quoted
 | |
|             ) )
 | |
|         else
 | |
|             toks=( ${toks[@]-} $(
 | |
|                 compgen -f -X "$xspec" -- $quoted
 | |
|             ) )
 | |
|         fi
 | |
|         if [ ${#toks[@]} -ne 0 ]; then
 | |
|             # If `compopt' is available, set `-o filenames'
 | |
|             compopt &>/dev/null && compopt -o filenames ||
 | |
|             # No, `compopt' isn't available;
 | |
|             # Is `-o filenames' set?
 | |
|             [[ (
 | |
|                 ${COMP_WORDS[0]} && 
 | |
|                 "$(complete -p ${COMP_WORDS[0]})" == *"-o filenames"*
 | |
|             ) ]] || {
 | |
|                 # No, `-o filenames' isn't set;
 | |
|                 # Emulate `-o filenames'
 | |
|                 # NOTE: A side-effect of emulating `-o filenames' is that
 | |
|                 #       backslash escape characters are visible within the list
 | |
|                 #       of presented completions, e.g.  the completions look
 | |
|                 #       like:
 | |
|                 #
 | |
|                 #           $ foo a<TAB>
 | |
|                 #           a\ b/  a\$b/
 | |
|                 #
 | |
|                 #       whereas with `-o filenames' active the completions look
 | |
|                 #       like:
 | |
|                 #
 | |
|                 #           $ ls a<TAB>
 | |
|                 #           a b/  a$b/
 | |
|                 #
 | |
|                 for ((i=0; i < ${#toks[@]}; i++)); do
 | |
|                     # If directory exists, append slash (/)
 | |
|                     if [[ ${cur:0:1} != "'" ]]; then
 | |
|                         [[ -d ${toks[i]} ]] && toks[i]="${toks[i]}"/
 | |
|                         if [[ ${cur:0:1} == '"' ]]; then
 | |
|                             toks[i]=${toks[i]//\\/\\\\}
 | |
|                             toks[i]=${toks[i]//\"/\\\"}
 | |
|                             toks[i]=${toks[i]//\$/\\\$}
 | |
|                         else
 | |
|                             toks[i]=$(printf %q ${toks[i]})
 | |
|                         fi
 | |
|                     fi
 | |
|                 done
 | |
|             }
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" )
 | |
| } # _filedir()
 | |
| 
 | |
| 
 | |
| # This function splits $cur=--foo=bar into $prev=--foo, $cur=bar, making it
 | |
| # easier to support both "--foo bar" and "--foo=bar" style completions.
 | |
| # Returns 0 if current option was split, 1 otherwise.
 | |
| #
 | |
| _split_longopt()
 | |
| {
 | |
|     if [[ "$cur" == --?*=* ]]; then
 | |
|         # Cut also backslash before '=' in case it ended up there
 | |
|         # for some reason.
 | |
|         prev="${cur%%?(\\)=*}"
 | |
|         cur="${cur#*=}"
 | |
|         return 0
 | |
|     fi
 | |
| 
 | |
|     return 1
 | |
| }
 | |
| 
 | |
| # This function tries to parse the output of $command --help
 | |
| #
 | |
| _parse_help() {
 | |
|     local cmd
 | |
|     cmd=$1
 | |
|     $cmd --help 2>&1 | command grep -- "^[[:space:]]*-" | tr "," " " | \
 | |
|         awk '{print $1; if ($2 ~ /-.*/) { print $2 } }' | sed -e "s:=.*::g"
 | |
| }
 | |
| 
 | |
| # This function completes on signal names
 | |
| #
 | |
| _signals()
 | |
| {
 | |
|     local i
 | |
| 
 | |
|     # standard signal completion is rather braindead, so we need
 | |
|     # to hack around to get what we want here, which is to
 | |
|     # complete on a dash, followed by the signal name minus
 | |
|     # the SIG prefix
 | |
|     COMPREPLY=( $( compgen -A signal SIG${cur#-} ))
 | |
|     for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
 | |
|         COMPREPLY[i]=-${COMPREPLY[i]#SIG}
 | |
|     done
 | |
| }
 | |
| 
 | |
| # This function completes on known mac addresses
 | |
| #
 | |
| _mac_addresses()
 | |
| {
 | |
|     local re='\([A-Fa-f0-9]\{2\}:\)\{5\}[A-Fa-f0-9]\{2\}'
 | |
|     local PATH="$PATH:/sbin:/usr/sbin"
 | |
| 
 | |
|     # Local interfaces (Linux only?)
 | |
|     COMPREPLY=( "${COMPREPLY[@]}" $( ifconfig -a 2>/dev/null | sed -ne \
 | |
|         "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" ) )
 | |
| 
 | |
|     # ARP cache
 | |
|     COMPREPLY=( "${COMPREPLY[@]}" $( arp -an 2>/dev/null | sed -ne \
 | |
|         "s/.*[[:space:]]\($re\)[[:space:]].*/\1/p" -ne \
 | |
|         "s/.*[[:space:]]\($re\)[[:space:]]*$/\1/p" ) )
 | |
| 
 | |
|     COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- "$cur" ) )
 | |
|     __ltrim_colon_completions "$cur"
 | |
| }
 | |
| 
 | |
| # This function completes on configured network interfaces
 | |
| #
 | |
| _configured_interfaces()
 | |
| {
 | |
|     if [ -f /etc/debian_version ]; then
 | |
|         # Debian system
 | |
|         COMPREPLY=( $( compgen -W "$( sed -ne 's|^iface \([^ ]\{1,\}\).*$|\1|p'\
 | |
|             /etc/network/interfaces )" -- "$cur" ) )
 | |
|     elif [ -f /etc/SuSE-release ]; then
 | |
|         # SuSE system
 | |
|         COMPREPLY=( $( compgen -W "$( printf '%s\n' \
 | |
|             /etc/sysconfig/network/ifcfg-* | \
 | |
|             sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) )
 | |
|     elif [ -f /etc/pld-release ]; then
 | |
|         # PLD Linux
 | |
|         COMPREPLY=( $( compgen -W "$( command ls -B \
 | |
|             /etc/sysconfig/interfaces | \
 | |
|             sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) )
 | |
|     else
 | |
|         # Assume Red Hat
 | |
|         COMPREPLY=( $( compgen -W "$( printf '%s\n' \
 | |
|             /etc/sysconfig/network-scripts/ifcfg-* | \
 | |
|             sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) )
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # This function completes on available kernels
 | |
| #
 | |
| _kernel_versions()
 | |
| {
 | |
|     COMPREPLY=( $( compgen -W '$( command ls /lib/modules )' -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on all available network interfaces
 | |
| # -a: restrict to active interfaces only
 | |
| # -w: restrict to wireless interfaces only
 | |
| #
 | |
| _available_interfaces()
 | |
| {
 | |
|     local cmd
 | |
| 
 | |
|     if [ "${1:-}" = -w ]; then
 | |
|         cmd="iwconfig"
 | |
|     elif [ "${1:-}" = -a ]; then
 | |
|         cmd="ifconfig"
 | |
|     else
 | |
|         cmd="ifconfig -a"
 | |
|     fi
 | |
| 
 | |
|     COMPREPLY=( $( eval PATH="$PATH:/sbin" $cmd 2>/dev/null | \
 | |
|         awk '/^[^ \t]/ { print $1 }' ) )
 | |
|     COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| 
 | |
| # Expand variable starting with tilde (~)
 | |
| # Only the first portion of the variable from the tilde up to the first slash
 | |
| # (~../) is expanded.  The remainder of the variable, containing for example
 | |
| # a dollar sign variable ($) or asterisk (*) is not expanded.
 | |
| # Example usage:
 | |
| #
 | |
| #    $ v="~"; __expand_tilde_by_ref v; echo "$v"
 | |
| #
 | |
| # Example output:
 | |
| #
 | |
| #       v                  output
 | |
| #    --------         ----------------
 | |
| #    ~                /home/user
 | |
| #    ~foo/bar         /home/foo/bar
 | |
| #    ~foo/$HOME       /home/foo/$HOME
 | |
| #    ~foo/a  b        /home/foo/a  b
 | |
| #    ~foo/*           /home/foo/*
 | |
| #  
 | |
| # @param $1  Name of variable (not the value of the variable) to expand
 | |
| __expand_tilde_by_ref() {
 | |
|     # Does $1 start with tilde (~)?
 | |
|     if [ "${!1:0:1}" = "~" ]; then
 | |
|         # Does $1 contain slash (/)?
 | |
|         if [ "${!1}" != "${!1//\/}" ]; then
 | |
|             # Yes, $1 contains slash;
 | |
|             # 1: Remove * including and after first slash (/), i.e. "~a/b"
 | |
|             #    becomes "~a".  Double quotes allow eval.
 | |
|             # 2: Remove * before the first slash (/), i.e. "~a/b"
 | |
|             #    becomes "b".  Single quotes prevent eval.
 | |
|             #                          +-----1----+ +---2----+
 | |
|             eval $1="${!1/%\/*}"/'${!1#*/}'
 | |
|         else 
 | |
|             # No, $1 doesn't contain slash
 | |
|             eval $1="${!1}"
 | |
|         fi
 | |
|     fi
 | |
| } # __expand_tilde_by_ref()
 | |
| 
 | |
| 
 | |
| # This function expands tildes in pathnames
 | |
| #
 | |
| _expand()
 | |
| {
 | |
|     # FIXME: Why was this here?
 | |
|     #[ "$cur" != "${cur%\\}" ] && cur="$cur\\"
 | |
| 
 | |
|     # Expand ~username type directory specifications.  We want to expand
 | |
|     # ~foo/... to /home/foo/... to avoid problems when $cur starting with
 | |
|     # a tilde is fed to commands and ending up quoted instead of expanded.
 | |
| 
 | |
|     if [[ "$cur" == \~*/* ]]; then
 | |
|         eval cur=$cur
 | |
|     elif [[ "$cur" == \~* ]]; then
 | |
|         cur=${cur#\~}
 | |
|         COMPREPLY=( $( compgen -P '~' -u "$cur" ) )
 | |
|         [ ${#COMPREPLY[@]} -eq 1 ] && eval COMPREPLY[0]=${COMPREPLY[0]}
 | |
|         return ${#COMPREPLY[@]}
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # This function completes on process IDs.
 | |
| # AIX and Solaris ps prefers X/Open syntax.
 | |
| [[ $UNAME == SunOS || $UNAME == AIX ]] &&
 | |
| _pids()
 | |
| {
 | |
|     COMPREPLY=( $( compgen -W '$( command ps -efo pid | sed 1d )' -- "$cur" ))
 | |
| } ||
 | |
| _pids()
 | |
| {
 | |
|     COMPREPLY=( $( compgen -W '$( command ps axo pid= )' -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on process group IDs.
 | |
| # AIX and SunOS prefer X/Open, all else should be BSD.
 | |
| [[ $UNAME == SunOS || $UNAME == AIX ]] &&
 | |
| _pgids()
 | |
| {
 | |
|     COMPREPLY=( $( compgen -W '$( command ps -efo pgid | sed 1d )' -- "$cur" ))
 | |
| } ||
 | |
| _pgids()
 | |
| {
 | |
|     COMPREPLY=( $( compgen -W '$( command ps axo pgid= )' -- "$cur" ))
 | |
| }
 | |
| 
 | |
| # This function completes on process names.
 | |
| # AIX and SunOS prefer X/Open, all else should be BSD.
 | |
| [[ $UNAME == SunOS || $UNAME == AIX ]] &&
 | |
| _pnames()
 | |
| {
 | |
|     COMPREPLY=( $( compgen -X '<defunct>' -W '$( command ps -efo comm | \
 | |
|         sed -e 1d -e "s:.*/::" -e "s/^-//" | sort -u )' -- "$cur" ) )
 | |
| } ||
 | |
| _pnames()
 | |
| {
 | |
|     # FIXME: completes "[kblockd/0]" to "0". Previously it was completed
 | |
|     # to "kblockd" which isn't correct either. "kblockd/0" would be
 | |
|     # arguably most correct, but killall from psmisc 22 treats arguments
 | |
|     # containing "/" specially unless -r is given so that wouldn't quite
 | |
|     # work either. Perhaps it'd be best to not complete these to anything
 | |
|     # for now.
 | |
|     # Not using "ps axo comm" because under some Linux kernels, it
 | |
|     # truncates command names (see e.g. http://bugs.debian.org/497540#19)
 | |
|     COMPREPLY=( $( compgen -X '<defunct>' -W '$( command ps axo command= | \
 | |
|         sed -e "s/ .*//" -e "s:.*/::" -e "s/:$//" -e "s/^[[(-]//" \
 | |
|             -e "s/[])]$//" | sort -u )' -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on user IDs
 | |
| #
 | |
| _uids()
 | |
| {
 | |
|     if type getent &>/dev/null; then
 | |
|         COMPREPLY=( $( compgen -W '$( getent passwd | cut -d: -f3 )' -- "$cur" ) )
 | |
|     elif type perl &>/dev/null; then
 | |
|         COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($uid) = (getpwent)[2]) { print $uid . "\n" }'"'"' )' -- "$cur" ) )
 | |
|     else
 | |
|         # make do with /etc/passwd
 | |
|         COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/passwd )' -- "$cur" ) )
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # This function completes on group IDs
 | |
| #
 | |
| _gids()
 | |
| {
 | |
|     if type getent &>/dev/null; then
 | |
|         COMPREPLY=( $( compgen -W '$( getent group | cut -d: -f3 )' \
 | |
|             -- "$cur" ) )
 | |
|     elif type perl &>/dev/null; then
 | |
|         COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($gid) = (getgrent)[2]) { print $gid . "\n" }'"'"' )' -- "$cur" ) )
 | |
|     else
 | |
|         # make do with /etc/group
 | |
|         COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/group )' -- "$cur" ) )
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # This function completes on services
 | |
| #
 | |
| _services()
 | |
| {
 | |
|     local sysvdir famdir
 | |
|     [ -d /etc/rc.d/init.d ] && sysvdir=/etc/rc.d/init.d || sysvdir=/etc/init.d
 | |
|     famdir=/etc/xinetd.d
 | |
|     COMPREPLY=( $( printf '%s\n' \
 | |
|         $sysvdir/!(*.rpm@(orig|new|save)|*~|functions) ) )
 | |
| 
 | |
|     if [ -d $famdir ]; then
 | |
|         COMPREPLY=( "${COMPREPLY[@]}" $( printf '%s\n' \
 | |
|             $famdir/!(*.rpm@(orig|new|save)|*~) ) )
 | |
|     fi
 | |
| 
 | |
|     COMPREPLY=( $( compgen -W '${COMPREPLY[@]#@($sysvdir|$famdir)/}' -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on modules
 | |
| #
 | |
| _modules()
 | |
| {
 | |
|     local modpath
 | |
|     modpath=/lib/modules/$1
 | |
|     COMPREPLY=( $( compgen -W "$( command ls -R $modpath | \
 | |
|         sed -ne 's/^\(.*\)\.k\{0,1\}o\(\.gz\)\{0,1\}$/\1/p' )" -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on installed modules
 | |
| #
 | |
| _installed_modules()
 | |
| {
 | |
|     COMPREPLY=( $( compgen -W "$( PATH="$PATH:/sbin" lsmod | \
 | |
|         awk '{if (NR != 1) print $1}' )" -- "$1" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on user or user:group format; as for chown and cpio.
 | |
| #
 | |
| # The : must be added manually; it will only complete usernames initially.
 | |
| # The legacy user.group format is not supported.
 | |
| #
 | |
| # It assumes compopt -o filenames; but doesn't touch it.
 | |
| _usergroup()
 | |
| {
 | |
|     local IFS=$'\n'
 | |
|     if [[ $cur = *\\\\* || $cur = *:*:* ]]; then
 | |
|         # Give up early on if something seems horribly wrong.
 | |
|         return
 | |
|     elif [[ $cur = *\\:* ]]; then
 | |
|         # Completing group after 'user\:gr<TAB>'.
 | |
|         # Reply with a list of groups prefixed with 'user:', readline will
 | |
|         # escape to the colon.
 | |
|         local prefix
 | |
|         prefix=${cur%%*([^:])}
 | |
|         prefix=${prefix//\\}
 | |
|         COMPREPLY=( $( compgen -P "$prefix" -g -- "${cur#*[:]}" ) )
 | |
|     elif [[ $cur = *:* ]]; then
 | |
|         # Completing group after 'user:gr<TAB>'.
 | |
|         # Reply with a list of unprefixed groups since readline with split on :
 | |
|         # and only replace the 'gr' part
 | |
|         COMPREPLY=( $( compgen -g -- "${cur#*:}" ) )
 | |
|     else
 | |
|         # Completing a partial 'usernam<TAB>'.
 | |
|         #
 | |
|         # Don't suffix with a : because readline will escape it and add a
 | |
|         # slash. It's better to complete into 'chown username ' than 'chown
 | |
|         # username\:'.
 | |
|         COMPREPLY=( $( compgen -u -- "$cur" ) )
 | |
|     fi
 | |
| }
 | |
| 
 | |
| # This function completes on valid shells
 | |
| #
 | |
| _shells()
 | |
| {
 | |
|     COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W \
 | |
|         '$( command grep "^[[:space:]]*/" /etc/shells 2>/dev/null )' \
 | |
|         -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on valid filesystem types
 | |
| #
 | |
| _fstypes()
 | |
| {
 | |
|     local fss
 | |
| 
 | |
|     if [ -e /proc/filesystems ] ; then
 | |
|         # Linux
 | |
|         fss="$( cut -d$'\t' -f2 /proc/filesystems )
 | |
|              $( awk '! /\*/ { print $NF }' /etc/filesystems 2>/dev/null )"
 | |
|     else
 | |
|         # Generic
 | |
|         fss="$( awk '/^[ \t]*[^#]/ { print $3 }' /etc/fstab 2>/dev/null )
 | |
|              $( awk '/^[ \t]*[^#]/ { print $3 }' /etc/mnttab 2>/dev/null )
 | |
|              $( awk '/^[ \t]*[^#]/ { print $4 }' /etc/vfstab 2>/dev/null )
 | |
|              $( awk '{ print $1 }' /etc/dfs/fstypes 2>/dev/null )
 | |
|              $( [ -d /etc/fs ] && command ls /etc/fs )"
 | |
|     fi
 | |
| 
 | |
|     [ -n "$fss" ] && \
 | |
|         COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$fss" -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # Get real command.
 | |
| # - arg: $1  Command
 | |
| # - stdout:  Filename of command in PATH with possible symbolic links resolved.
 | |
| #            Empty string if command not found.
 | |
| # - return:  True (0) if command found, False (> 0) if not.
 | |
| _realcommand()
 | |
| {
 | |
|     type -P "$1" > /dev/null && {
 | |
|         if type -p realpath > /dev/null; then
 | |
|             realpath "$(type -P "$1")"
 | |
|         elif type -p readlink > /dev/null; then
 | |
|             readlink -f "$(type -P "$1")"
 | |
|         else
 | |
|             type -P "$1"
 | |
|         fi
 | |
|     }
 | |
| }
 | |
| 
 | |
| # This function returns the first arugment, excluding options
 | |
| # @param $1 chars  Characters out of $COMP_WORDBREAKS which should
 | |
| #     NOT be considered word breaks. See __reassemble_comp_words_by_ref.
 | |
| _get_first_arg()
 | |
| {
 | |
|     local i
 | |
| 
 | |
|     arg=
 | |
|     for (( i=1; i < COMP_CWORD; i++ )); do
 | |
|         if [[ "${COMP_WORDS[i]}" != -* ]]; then
 | |
|             arg=${COMP_WORDS[i]}
 | |
|             break
 | |
|         fi
 | |
|     done
 | |
| }
 | |
| 
 | |
| 
 | |
| # This function counts the number of args, excluding options
 | |
| # @param $1 chars  Characters out of $COMP_WORDBREAKS which should
 | |
| #     NOT be considered word breaks. See __reassemble_comp_words_by_ref.
 | |
| _count_args()
 | |
| {
 | |
|     local i cword words
 | |
|     __reassemble_comp_words_by_ref "$1" words cword
 | |
| 
 | |
|     args=1
 | |
|     for i in "${words[@]:1:cword-1}"; do
 | |
|         [[ "$i" != -* ]] && args=$(($args+1))
 | |
|     done
 | |
| }
 | |
| 
 | |
| # This function completes on PCI IDs
 | |
| #
 | |
| _pci_ids()
 | |
| {
 | |
|     COMPREPLY=( ${COMPREPLY[@]:-} $( compgen -W \
 | |
|         "$( PATH="$PATH:/sbin" lspci -n | awk '{print $3}')" -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # This function completes on USB IDs
 | |
| #
 | |
| _usb_ids()
 | |
| {
 | |
|     COMPREPLY=( ${COMPREPLY[@]:-} $( compgen -W \
 | |
|         "$( PATH="$PATH:/sbin" lsusb | awk '{print $6}' )" -- "$cur" ) )
 | |
| }
 | |
| 
 | |
| # CD device names
 | |
| _cd_devices()
 | |
| {
 | |
|     COMPREPLY=( "${COMPREPLY[@]}"
 | |
|         $( compgen -f -d -X "!*/?([amrs])cd*" -- "${cur:-/dev/}" ) )
 | |
| }
 | |
| 
 | |
| # DVD device names
 | |
| _dvd_devices()
 | |
| {
 | |
|     COMPREPLY=( "${COMPREPLY[@]}"
 | |
|         $( compgen -f -d -X "!*/?(r)dvd*" -- "${cur:-/dev/}" ) )
 | |
| }
 | |
| ##--end[RIPPED from /etc/bash_completion-------------------------------------]--
 | |
| 
 | |
| ##--start[RIPPED from /etc/bash_completion-----------------------------------]--
 | |
| # start of section containing completion functions for external programs
 | |
| 
 | |
| # This function provides simple user@host completion
 | |
| #
 | |
| _user_at_host() {
 | |
|     local cur
 | |
| 
 | |
|     COMPREPLY=()
 | |
|     _get_comp_words_by_ref -n : cur
 | |
| 
 | |
|     if [[ $cur == *@* ]]; then
 | |
|         _known_hosts_real "$cur"
 | |
|     else
 | |
|         COMPREPLY=( $( compgen -u -- "$cur" ) )
 | |
|     fi
 | |
| 
 | |
|     return 0
 | |
| }
 | |
| shopt -u hostcomplete && complete -F _user_at_host -o nospace talk ytalk finger
 | |
| 
 | |
| # NOTE: Using this function as a helper function is deprecated.  Use
 | |
| #       `_known_hosts_real' instead.
 | |
| _known_hosts()
 | |
| {
 | |
|     local options
 | |
|     COMPREPLY=()
 | |
| 
 | |
|     # NOTE: Using `_known_hosts' as a helper function and passing options
 | |
|     #       to `_known_hosts' is deprecated: Use `_known_hosts_real' instead.
 | |
|     [[ "$1" == -a || "$2" == -a ]] && options=-a
 | |
|     [[ "$1" == -c || "$2" == -c ]] && options="$options -c"
 | |
|     _known_hosts_real $options "$(_get_cword :)"
 | |
| } # _known_hosts()
 | |
| 
 | |
| # Helper function for completing _known_hosts.
 | |
| # This function performs host completion based on ssh's config and known_hosts
 | |
| # files, as well as hostnames reported by avahi-browse.  Also hosts from
 | |
| # HOSTFILE (compgen -A hostname) are added, unless
 | |
| # COMP_KNOWN_HOSTS_WITH_HOSTFILE is set to an empty value.
 | |
| # Usage: _known_hosts_real [OPTIONS] CWORD
 | |
| # Options:  -a             Use aliases
 | |
| #           -c             Use `:' suffix
 | |
| #           -F configfile  Use `configfile' for configuration settings
 | |
| #           -p PREFIX      Use PREFIX
 | |
| # Return: Completions, starting with CWORD, are added to COMPREPLY[]
 | |
| _known_hosts_real()
 | |
| {
 | |
|     local configfile flag prefix
 | |
|     local cur curd awkcur user suffix aliases i host
 | |
|     local -a kh khd config
 | |
| 
 | |
|     local OPTIND=1
 | |
|     while getopts "acF:p:" flag "$@"; do
 | |
|         case $flag in
 | |
|             a) aliases='yes' ;;
 | |
|             c) suffix=':' ;;
 | |
|             F) configfile=$OPTARG ;;
 | |
|             p) prefix=$OPTARG ;;
 | |
|         esac
 | |
|     done
 | |
|     [ $# -lt $OPTIND ] && echo "error: $FUNCNAME: missing mandatory argument CWORD"
 | |
|     cur=${!OPTIND}; let "OPTIND += 1"
 | |
|     [ $# -ge $OPTIND ] && echo "error: $FUNCNAME("$@"): unprocessed arguments:"\
 | |
|     $(while [ $# -ge $OPTIND ]; do printf '%s\n' ${!OPTIND}; shift; done)
 | |
| 
 | |
|     [[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@}
 | |
|     kh=()
 | |
| 
 | |
|     # ssh config files
 | |
|     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
 | |
| 
 | |
|     # Known hosts files from configs
 | |
|     if [ ${#config[@]} -gt 0 ]; then
 | |
|         local OIFS=$IFS IFS=$'\n'
 | |
|         local -a tmpkh
 | |
|         # expand paths (if present) to global and user known hosts files
 | |
|         # TODO(?): try to make known hosts files with more than one consecutive
 | |
|         #          spaces in their name work (watch out for ~ expansion
 | |
|         #          breakage! Alioth#311595)
 | |
|         tmpkh=( $( awk 'sub("^[ \t]*([Gg][Ll][Oo][Bb][Aa][Ll]|[Uu][Ss][Ee][Rr])[Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][ \t]+", "") { print $0 }' "${config[@]}" | sort -u ) )
 | |
|         for i in "${tmpkh[@]}"; do
 | |
|             # Remove possible quotes
 | |
|             i=${i//\"}
 | |
|             # Eval/expand possible `~' or `~user'
 | |
|             __expand_tilde_by_ref i
 | |
|             [ -r "$i" ] && kh=( "${kh[@]}" "$i" )
 | |
|         done
 | |
|         IFS=$OIFS
 | |
|     fi
 | |
| 
 | |
|     # Global known_hosts files
 | |
|     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
 | |
|     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 || ${#khd[@]} -gt 0 ]]; then
 | |
|         # Escape slashes and dots in paths for awk
 | |
|         awkcur=${cur//\//\\\/}
 | |
|         awkcur=${awkcur//\./\\\.}
 | |
|         curd=$awkcur
 | |
| 
 | |
|         if [[ "$awkcur" == [0-9]*.* ]]; then
 | |
|             # Digits followed by a dot - just search for that
 | |
|             awkcur="^$awkcur.*"
 | |
|         elif [[ "$awkcur" == [0-9]* ]]; then
 | |
|             # Digits followed by no dot - search for digits followed
 | |
|             # by a dot
 | |
|             awkcur="^$awkcur.*\."
 | |
|         elif [ -z "$awkcur" ]; then
 | |
|             # A blank - search for a dot or an alpha character
 | |
|             awkcur="[a-z.]"
 | |
|         else
 | |
|             awkcur="^$awkcur"
 | |
|         fi
 | |
| 
 | |
|         if [ ${#kh[@]} -gt 0 ]; then
 | |
|             # FS needs to look for a comma separated list
 | |
|             COMPREPLY=( "${COMPREPLY[@]}" $( awk 'BEGIN {FS=","}
 | |
|             /^\s*[^|\#]/ {for (i=1; i<=2; ++i) { \
 | |
|             gsub(" .*$", "", $i); \
 | |
|             gsub("[\\[\\]]", "", $i); \
 | |
|             gsub(":[0-9]+$", "", $i); \
 | |
|             if ($i ~ /'"$awkcur"'/) {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
 | |
| 
 | |
|         # apply suffix and prefix
 | |
|         for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
 | |
|             COMPREPLY[i]=$prefix$user${COMPREPLY[i]}$suffix
 | |
|         done
 | |
|     fi
 | |
| 
 | |
|     # append any available aliases from config files
 | |
|     if [[ ${#config[@]} -gt 0 && -n "$aliases" ]]; then
 | |
|         local hosts=$( sed -ne 's/^[ \t]*[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\{0,1\}['"$'\t '"']\{1,\}\([^#*?]*\)\(#.*\)\{0,1\}$/\2/p' "${config[@]}" )
 | |
|         COMPREPLY=( "${COMPREPLY[@]}" $( compgen  -P "$prefix$user" \
 | |
|             -S "$suffix" -W "$hosts" -- "$cur" ) )
 | |
|     fi
 | |
| 
 | |
|     # Add hosts reported by avahi-browse, if it's available.
 | |
|     # The original call to avahi-browse also had "-k", to avoid lookups into
 | |
|     # avahi's services DB. We don't need the name of the service, and if it
 | |
|     # contains ";", it may mistify the result. But on Gentoo (at least),
 | |
|     # -k isn't available (even if mentioned in the manpage), so...
 | |
|     if type avahi-browse >&/dev/null; then
 | |
|         COMPREPLY=( "${COMPREPLY[@]}" $( \
 | |
|             compgen -P "$prefix$user" -S "$suffix" -W \
 | |
|             "$( avahi-browse -cpr _workstation._tcp 2>/dev/null | \
 | |
|                  awk -F';' '/^=/ { print $7 }' | sort -u )" -- "$cur" ) )
 | |
|     fi
 | |
| 
 | |
|     # Add results of normal hostname completion, unless
 | |
|     # `COMP_KNOWN_HOSTS_WITH_HOSTFILE' is set to an empty value.
 | |
|     if [ -n "${COMP_KNOWN_HOSTS_WITH_HOSTFILE-1}" ]; then
 | |
|         COMPREPLY=( "${COMPREPLY[@]}"
 | |
|             $( compgen -A hostname -P "$prefix$user" -S "$suffix" -- "$cur" ) )
 | |
|     fi
 | |
| 
 | |
|     __ltrim_colon_completions "$prefix$user$cur"
 | |
| 
 | |
|     return 0
 | |
| } # _known_hosts_real()
 | |
| ##--end[RIPPED from /etc/bash_completion-------------------------------------]--
 | |
| 
 | |
| ##--start[RIPPED from /etc/bash_completion-----------------------------------]--
 | |
| # a wrapper method for the next one, when the offset is unknown
 | |
| _command()
 | |
| {
 | |
|     local offset i
 | |
| 
 | |
|     # find actual offset, as position of the first non-option
 | |
|     offset=1
 | |
|     for (( i=1; i <= COMP_CWORD; i++ )); do
 | |
|         if [[ "${COMP_WORDS[i]}" != -* ]]; then
 | |
|             offset=$i
 | |
|             break
 | |
|         fi
 | |
|     done
 | |
|     _command_offset $offset
 | |
| }
 | |
| 
 | |
| # A meta-command completion function for commands like sudo(8), which need to
 | |
| # first complete on a command, then complete according to that command's own
 | |
| # completion definition - currently not quite foolproof (e.g. mount and umount
 | |
| # don't work properly), but still quite useful.
 | |
| #
 | |
| _command_offset()
 | |
| {
 | |
|     local cur func cline cspec noglob cmd i char_offset word_offset \
 | |
|         _COMMAND_FUNC _COMMAND_FUNC_ARGS
 | |
| 
 | |
|     word_offset=$1
 | |
| 
 | |
|     # rewrite current completion context before invoking
 | |
|     # actual command completion
 | |
| 
 | |
|     # find new first word position, then
 | |
|     # rewrite COMP_LINE and adjust COMP_POINT
 | |
|     local first_word=${COMP_WORDS[$word_offset]}
 | |
|     for (( i=0; i <= ${#COMP_LINE}; i++ )); do
 | |
|         if [[ "${COMP_LINE:$i:${#first_word}}" == "$first_word" ]]; then
 | |
|             char_offset=$i
 | |
|             break
 | |
|         fi
 | |
|     done
 | |
|     COMP_LINE=${COMP_LINE:$char_offset}
 | |
|     COMP_POINT=$(( COMP_POINT - $char_offset ))
 | |
| 
 | |
|     # shift COMP_WORDS elements and adjust COMP_CWORD
 | |
|     for (( i=0; i <= COMP_CWORD - $word_offset; i++ )); do
 | |
|         COMP_WORDS[i]=${COMP_WORDS[i+$word_offset]}
 | |
|     done
 | |
|     for (( i; i <= COMP_CWORD; i++ )); do
 | |
|         unset COMP_WORDS[i];
 | |
|     done
 | |
|     COMP_CWORD=$(( $COMP_CWORD - $word_offset ))
 | |
| 
 | |
|     COMPREPLY=()
 | |
|     _get_comp_words_by_ref cur
 | |
| 
 | |
|     if [[ $COMP_CWORD -eq 0 ]]; then
 | |
|         COMPREPLY=( $( compgen -c -- "$cur" ) )
 | |
|     else
 | |
|         cmd=${COMP_WORDS[0]}
 | |
|         if complete -p $cmd &>/dev/null; then
 | |
|             cspec=$( complete -p $cmd )
 | |
|             if [ "${cspec#* -F }" != "$cspec" ]; then
 | |
|                 # complete -F <function>
 | |
| 
 | |
|                 # get function name
 | |
|                 func=${cspec#*-F }
 | |
|                 func=${func%% *}
 | |
| 
 | |
|                 if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then
 | |
|                     $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}"
 | |
|                 else
 | |
|                     $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}"
 | |
|                 fi
 | |
| 
 | |
|                 # remove any \: generated by a command that doesn't
 | |
|                 # default to filenames or dirnames (e.g. sudo chown)
 | |
|                 # FIXME: I'm pretty sure this does not work!
 | |
|                 if [ "${cspec#*-o }" != "$cspec" ]; then
 | |
|                     cspec=${cspec#*-o }
 | |
|                     cspec=${cspec%% *}
 | |
|                     if [[ "$cspec" != @(dir|file)names ]]; then
 | |
|                         COMPREPLY=("${COMPREPLY[@]//\\\\:/:}")
 | |
|                     fi
 | |
|                 fi
 | |
|             elif [ -n "$cspec" ]; then
 | |
|                 cspec=${cspec#complete};
 | |
|                 cspec=${cspec%%$cmd};
 | |
|                 COMPREPLY=( $( eval compgen "$cspec" -- "$cur" ) );
 | |
|             fi
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     [ ${#COMPREPLY[@]} -eq 0 ] && _filedir
 | |
| }
 | |
| ##--end[RIPPED from /etc/bash_completion-------------------------------------]--
 | |
| 
 | |
| ##--start[RIPPED from /etc/bash_completion-----------------------------------]--
 | |
| _root_command()
 | |
| {
 | |
|     local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin
 | |
|     _command $1 $2 $3
 | |
| }
 | |
| ##--end[RIPPED from /etc/bash_completion-------------------------------------]--
 | |
| 
 | |
| ##--start[RIPPED from /etc/bash_completion-----------------------------------]--
 | |
| _longopt()
 | |
| {
 | |
|     local cur prev
 | |
| 
 | |
|     _get_comp_words_by_ref cur prev
 | |
| 
 | |
|     if _split_longopt; then
 | |
|         case "$prev" in
 | |
|             *[Dd][Ii][Rr]*)
 | |
|                 _filedir -d
 | |
|                 ;;
 | |
|             *[Ff][Ii][Ll][Ee]*)
 | |
|                 _filedir
 | |
|                 ;;
 | |
|         esac
 | |
|         return 0
 | |
|     fi
 | |
| 
 | |
|     if [[ "$cur" == -* ]]; then
 | |
|         COMPREPLY=( $( compgen -W "$( $1 --help 2>&1 | \
 | |
|             sed -ne 's/.*\(--[-A-Za-z0-9]\{1,\}\).*/\1/p' | sort -u )" \
 | |
|             -- "$cur" ) )
 | |
|     elif [[ "$1" == rmdir ]]; then
 | |
|         _filedir -d
 | |
|     else
 | |
|         _filedir
 | |
|     fi
 | |
| }
 | |
| ##--end[RIPPED from /etc/bash_completion-------------------------------------]--
 | |
| 
 | |
| ##--start[RIPPED from /etc/bash_completion-----------------------------------]--
 | |
| _filedir_xspec()
 | |
| {
 | |
|     local IFS cur xspec
 | |
| 
 | |
|     IFS=$'\t\n'
 | |
|     COMPREPLY=()
 | |
|     _get_comp_words_by_ref cur
 | |
| 
 | |
|     _expand || return 0
 | |
| 
 | |
|     # get first exclusion compspec that matches this command
 | |
|     xspec=$( awk "/^complete[ \t]+.*[ \t]${1##*/}([ \t]|\$)/ { print \$0; exit }" \
 | |
|         "$BASH_COMPLETION" )
 | |
|     # prune to leave nothing but the -X spec
 | |
|     xspec=${xspec#*-X }
 | |
|     xspec=${xspec%% *}
 | |
| 
 | |
|     local -a toks
 | |
|     local tmp
 | |
| 
 | |
|     toks=( ${toks[@]-} $(
 | |
|         compgen -d -- "$(quote_readline "$cur")" | {
 | |
|         while read -r tmp; do
 | |
|             # see long TODO comment in _filedir() --David
 | |
|             printf '%s\n' $tmp
 | |
|         done
 | |
|         }
 | |
|         ))
 | |
| 
 | |
|     toks=( ${toks[@]-} $(
 | |
|         eval compgen -f -X "$xspec" -- "\$(quote_readline "\$cur")" | {
 | |
|         while read -r tmp; do
 | |
|             [ -n $tmp ] && printf '%s\n' $tmp
 | |
|         done
 | |
|         }
 | |
|         ))
 | |
| 
 | |
|     COMPREPLY=( "${toks[@]}" )
 | |
| }
 | |
| ##--end[RIPPED from /etc/bash_completion-------------------------------------]--
 | |
| fi
 |