Completion files

Since v2.05a, bash has offered intelligent programmable completion. Writing such completions for your own programs/things you maintain is relatively easy provided you know bash already. See bash-completion-r1.eclass for how to install completion files.

Most of these variables lose their special properties when unset, even if they are subsequently reset.

Variable Purpose
COMP_CWORD An index into ${COMP_WORDS} of the word containing the current cursor position.
COMP_LINE The current command line.
COMP_POINT The index of the current cursor position relative to the beginning of the current command. If the current cursor position is at the end of the current command, the value of this variable is equal to ${#COMP_LINE}.
COMP_WORDBREAKS The set of characters that the Readline library treats as word separators when performing word completion.
COMP_WORDS An array variable consisting of the individual words in the current command line, ${COMP_LINE}.
COMPREPLY An array variable from which bash reads the possible completions generated by a completion function.

See man bash for a full description of these builtins and their options.

Builtin Usage
compgen compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-P prefix] [-S suffix] [-X filterpat] [-F function] [-C command] [word] Display the possible completions depending on the options. Intended to be used from within a shell function generating possible completions. If the optional WORD argument is supplied, matches against WORD are generated.
complete complete [-abcdefgjksuv] [-pr] [-o option] [-A action] [-G globpat] [-W wordlist] [-P prefix] [-S suffix] [-X filterpat] [-F function] [-C command] [name ...] For each NAME, specify how arguments are to be completed. If the -p option is supplied, or if no options are supplied, existing completion specifications are printed in a way that allows them to be reused as input. The -r option removes a completion specification for each NAME, or, if no NAMEs are supplied, all completion specifications.

For extremely simple cases, a simple complete statement is all that is needed. For example, minimal cd completion (minimal as in no support for ${CDPATH}) would be as simple as:

complete -o nospace -d cd

Anatomy of a completion function

Nearly all completion functions will start out the same way. For these cases, the following can be used as a template for creating new completion functions:

01: _foo() {
02: 	local cur prev opts
04: 	cur="${COMP_WORDS[COMP_CWORD]}"
05: 	prev="${COMP_WORDS[COMP_CWORD-1]}"
06: 	opts=""
08: 	if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
09: 		COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
10: 		return 0
11: 	fi
13: 	case "${prev}" in
14: 		# ...
15: 	esac
16: }
17: complete -F _foo foo
Line Explanation
1 The convention for completion function names is usually _NAME, where NAME is the name of the application/function you are writing the completion function for. If NAME contains a '-', it should be replaced with a '_'. Hence bash-completion-config would be _bash_completion_config(). Failing to do so can cause weird bugs if bash is invoked in POSIX-mode while a function name containing a '-' is in the environment (POSIX sh does not allow a '-' in function names).
3 Resets the ${COMPREPLY} array, as it may be set from a previous invocation.
4 Sets the local variable, ${cur} to the current word of the command line. If the current command line, ${COMP_LINE} is say 'foo --fil', ${cur} would be equal to '--fil'. If ${COMP_LINE} is equal to 'foo --file ' (note the space at the end), ${cur} is null.
5 Sets the local variable, ${prev} to the previous word of the command line. ${prev} is the word before ${cur}.
6 Sets the local variable, ${opts}. In a real completion function, this variable would be set to all the options that foo recognizes.
8 Tests whether or not the current word is equivalent to -* (an option) or if we're completing on the first word (ie. ${COMP_CWORD} == 1).
9 If the test returns true, show the available options, ${opts}. The -W option to compgen tells bash to complete on the word list (string or something that evaluates to a string). In the majority of cases, you'll pass -- ${cur} to compgen telling it to only return those completions that match ${cur}.
13 Most of the time, you'll want to perform a certain action if ${prev} is equal to a certain option. For example, if foo has a --file option (and -f for short) that takes any kind file, you could do:
case "${prev}" in
		COMPREPLY=( $(compgen -f ? ${cur}) )
17 Tells bash to use the _foo function to generate any completions for the foo application/function.

Real-world example

For this document, I will take you through a real-world example and write a real completion function for revdep-rebuild (might even be available in gentoo-bashcomp by the time you read this :]).

01: _revdep_rebuild() {
02: 	local cur prev opts
04: 	cur="${COMP_WORDS[COMP_CWORD]}"
05: 	prev="${COMP_WORDS[COMP_CWORD-1]}"
06: 	opts="-X --package-names --soname --soname-regexp -q --quiet"
08: 	if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] || \
09: 	   [[ ${prev} == @(-q|--quiet) ]] ; then
10: 		COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
11: 		return 0
12: 	fi
14: 	case "${prev}" in
15: 		-X|--package-names)
16: 			_pkgname -I ${cur}
17: 			;;
18: 		--soname)
19: 			local sonames=$(for x in /lib/*.so?(.)* /usr/lib*/*.so\?(.)* ; do \
20: 						echo ${x##*/} ; \
21: 						done)
22: 			COMPREPLY=( $(compgen -W "${sonames}" -- ${cur}) )
23: 			;;
24: 		--soname-regexp)
25: 			COMPREPLY=()
26: 			;;
27: 		*)
28: 			if [[ ${COMP_LINE} == *" "@(-X|--package-names)* ]] ; then
29: 				_pkgname -I ${cur}
30: 				COMPREPLY=(${COMPREPLY[@]} $(compgen -W "${opts}"))
31: 			else
32: 				COMPREPLY=($(compgen -W "${opts} -- ${cur}"))
33: 			fi
34: 		;;
35: 	esac
36: }
37: complete -F _revdep_rebuild revdep-rebuild

Lines 1-12 are pretty much the same as in the previous section.

Line Explanation
15 If ${prev} is equal to -X or --package-names, call _pkgname (a function defined by gentoo-bashcomp that completes on package names — it sets ${COMPREPLY}, so we don't worry about that here).
18 If ${prev} is equal to --soname, generate a list of all shared libs in /lib and /usr/lib*. Pass that list to compgen to generate a list of possible completions that match ${cur}.
24 Obviously we cannot complete on any regexp's so if ${prev} is equal to --soname-regexp, do nothing.
27 For anything else (any options not specified in the case statement above OR any argument to one of the options specified in the case statement) perform the tests. Since --package-names can take multiple package names, we want to continue to complete on package names until another recognized option is encountered (ie. is ${prev}).
30 Since _pkgname sets ${COMPREPLY} and we want to add to that list, we have to use the COMPREPLY=(${COMPREPLY[@] ... ) construct.
37 Tell bash to use _revdep_rebuild to generate all possible completions for revdep-rebuild.