The bash-completion is a package for completing command argument. This article will describe how to implement bash-completion script for original command.
Table of Contents
1 bash-completion
The bash-completion is a package for completing command argument. Each command package provides bash-completion's bash script (There are some command package which does not provides).
For example, find command provides bash-completion script. This will show candidate list for argument. An argument will be written to bash when there is one candidate.
$ find / -type b c d f l p s
bash-completion script is loaded with . or source.
$ . <bash-completion>
bash-completion script in the following directory will be loaded when starting bash.
/etc/bash_completion.d/ /usr/share/bash-completion/completions/
2 bash-completion script
The __example_bash_completion implements completion for example command.
_have example && \ __example_bash_completion() { # Create argument list with checking previous argument. # Create COMPREPLY from argument list. } && \ complete -F __example_bash_completion example
- The _have which is bash-completion's builtin function will check if example command is exists or not. If example command is exists, __example_bash_completion function will be defined, and the complete which is bash-completion's builtin function will be done.
- The complete maps __example_bash_completion function and example command.
- The __example_bash_completion function implements completion for example command with assigning candidates to COMPREPLY array.
- The completion function name should have underscore prefix. This is for distinguish fompletion function name and command name. If completion function does not have underscore prefix, completion function will be show when command completion.
- The 3rd argument of completion function is previous argument of command.The 2nd argument of completion function is current argument of command.
$ example # ${3} is example, ${2} is empty. $ exapmle arg # ${3} is example, ${2} is arg. $ exapmle arg1 ar # ${3} is arg1, ${2} is ar.
3 Example command which has ordered argument
Define the following command which has ordered argument.
$ food <food> <method>
- <food> is "bacon" or "egg".
- If <food> is "bacon", <method> is unused.
- If <food> is "egg", <method> is "boiled" or "fried".
The all pattern of command is the following.
$ food bacon $ food egg boiled $ food egg fried
The bash-completion is the following.
_have food && \ __food_bash_completion() { # Create argument list with checking previous argument. local args case "${3}" in food) args="bacon egg";; egg) args="boiled fried";; *) return;; esac # Create COMPREPLY from argument list. if [ -z "${2}" ]; then COMPREPLY=(${args}) else local arg compreply="" # Append forward matched string with ${2}. for arg in ${args}; do [ "${arg#${2}}" != "${arg}" ] && compreply="${arg} ${compreply}" done COMPREPLY=(${compreply}) fi } && \ complete -F __food_bash_completion food
- The [ -z "${2}" ] false case is, for example, when typing TAB key to "food b", Remove candidate which does not have "b" prefix.
4 Example command which has unordered argument
Define the following command which has unordered argument.
$ drink <drink> [--with <add>] $ drink --with <add> <drink>
- <drink> is "coffee" or "tea".
- <add> is "sugar" or "milk".
- Either <drink> or –with can be first.
The all pattern of command is the following.
$ drink coffee $ drink coffee --with sugar $ drink coffee --with milk $ drink --with sugar coffee $ drink --with milk coffee $ drink tea $ drink tea --with sugar $ drink tea --with milk $ drink --with sugar tea $ drink --with milk tea
The bash-completion is the following.
_have drink && \ __drink_bash_completion() { # Assigned variable by _init_completion. # cur Current argument. # prev Previous argument. # words Argument array. # cword Argument array size. local cur prev words cword _init_completion || return # Flag for checking if argument is used or not. local used_drink=0 used_with=0 # Check used argument. local word for word in ${words[@]}; do case ${word} in coffee|tea) used_drink=1;; --with) used_with=1;; esac done # Create argument list with checking previous argument. local args case "${prev}" in --with) args="sugar milk" ;; *) # Append unused argument. [ ${used_drink} -eq 0 ] && args="coffee tea" [ ${used_with} -eq 0 ] && args="${args} --with" ;; esac # Create COMPREPLY from argument list. if [ -z "${cur}" ]; then COMPREPLY=(${args}) else local arg compreply="" # Append matched string with cur. for arg in ${args}; do [ "${arg#${cur}}" != "${arg}" ] && compreply="${arg} ${compreply}" done COMPREPLY=(${compreply}) fi } && \ complete -F __drink_bash_completion drink
- The _init_completion which is bash-completion's builtin function will get argument list which have been set already. The variables cur, prev, words and cword must be defined before calling _init_completion because these variables are used in _init_completion.
- The cur is the same with the 2nd argument of completion function. The prev is the same with the 3rd argument of completion function.
- The words have argument list which have been set already. The cwords is size of this array.
- Using the words can check if <drink> argument is used or not, and check if –with argument is used or not.