bash: A Programmable Completion Example
1
1 8.8 A Programmable Completion Example
1 =====================================
1
1 The most common way to obtain additional completion functionality beyond
1 the default actions 'complete' and 'compgen' provide is to use a shell
1 function and bind it to a particular command using 'complete -F'.
1
1 The following function provides completions for the 'cd' builtin. It
1 is a reasonably good example of what shell functions must do when used
1 for completion. This function uses the word passsed as '$2' to
1 determine the directory name to complete. You can also use the
1 'COMP_WORDS' array variable; the current word is indexed by the
1 'COMP_CWORD' variable.
1
1 The function relies on the 'complete' and 'compgen' builtins to do
1 much of the work, adding only the things that the Bash 'cd' does beyond
11 accepting basic directory names: tilde expansion (⇒Tilde
Expansion), searching directories in $CDPATH, which is described above
1 (⇒Bourne Shell Builtins), and basic support for the 'cdable_vars'
1 shell option (⇒The Shopt Builtin). '_comp_cd' modifies the value
1 of IFS so that it contains only a newline to accommodate file names
1 containing spaces and tabs - 'compgen' prints the possible completions
1 it generates one per line.
1
1 Possible completions go into the COMPREPLY array variable, one
1 completion per array element. The programmable completion system
1 retrieves the completions from there when the function returns.
1
1 # A completion function for the cd builtin
1 # based on the cd completion function from the bash_completion package
1 _comp_cd()
1 {
1 local IFS=$' \t\n' # normalize IFS
1 local cur _skipdot _cdpath
1 local i j k
1
1 # Tilde expansion, with side effect of expanding tilde to full pathname
1 case "$2" in
1 \~*) eval cur="$2" ;;
1 *) cur=$2 ;;
1 esac
1
1 # no cdpath or absolute pathname -- straight directory completion
1 if [[ -z "${CDPATH:-}" ]] || [[ "$cur" == @(./*|../*|/*) ]]; then
1 # compgen prints paths one per line; could also use while loop
1 IFS=$'\n'
1 COMPREPLY=( $(compgen -d -- "$cur") )
1 IFS=$' \t\n'
1 # CDPATH+directories in the current directory if not in CDPATH
1 else
1 IFS=$'\n'
1 _skipdot=false
1 # preprocess CDPATH to convert null directory names to .
1 _cdpath=${CDPATH/#:/.:}
1 _cdpath=${_cdpath//::/:.:}
1 _cdpath=${_cdpath/%:/:.}
1 for i in ${_cdpath//:/$'\n'}; do
1 if [[ $i -ef . ]]; then _skipdot=true; fi
1 k="${#COMPREPLY[@]}"
1 for j in $( compgen -d -- "$i/$cur" ); do
1 COMPREPLY[k++]=${j#$i/} # cut off directory
1 done
1 done
1 $_skipdot || COMPREPLY+=( $(compgen -d -- "$cur") )
1 IFS=$' \t\n'
1 fi
1
1 # variable names if appropriate shell option set and no completions
1 if shopt -q cdable_vars && [[ ${#COMPREPLY[@]} -eq 0 ]]; then
1 COMPREPLY=( $(compgen -v -- "$cur") )
1 fi
1
1 return 0
1 }
1
1 We install the completion function using the '-F' option to
1 'complete':
1
1 # Tell readline to quote appropriate and append slashes to directories;
1 # use the bash default completion for other arguments
1 complete -o filenames -o nospace -o bashdefault -F _comp_cd cd
1
1 Since we'd like Bash and Readline to take care of some of the other
1 details for us, we use several other options to tell Bash and Readline
1 what to do. The '-o filenames' option tells Readline that the possible
1 completions should be treated as filenames, and quoted appropriately.
1 That option will also cause Readline to append a slash to filenames it
1 can determine are directories (which is why we might want to extend
1 '_comp_cd' to append a slash if we're using directories found via
1 CDPATH: Readline can't tell those completions are directories). The '-o
1 nospace' option tells Readline to not append a space character to the
1 directory name, in case we want to append to it. The '-o bashdefault'
1 option brings in the rest of the "Bash default" completions - possible
1 completion that Bash adds to the default Readline set. These include
1 things like command name completion, variable completion for words
1 beginning with '{', completions containing pathname expansion patterns
1 (⇒Filename Expansion), and so on.
1
1 Once installed using 'complete', '_comp_cd' will be called every time
1 we attempt word completion for a 'cd' command.
1
1 Many more examples - an extensive collection of completions for most
1 of the common GNU, Unix, and Linux commands - are available as part of
1 the bash_completion project. This is installed by default on many
1 GNU/Linux distributions. Originally written by Ian Macdonald, the
1 project now lives at <http://bash-completion.alioth.debian.org/>. There
1 are ports for other systems such as Solaris and Mac OS X.
1
1 An older version of the bash_completion package is distributed with
1 bash in the 'examples/complete' subdirectory.
1