How to make autocomplete for any bash commands
Stolen and awkwardly translated from here, with a few additions.
Simple version — static list
Suppose there is a command dothis. Let’s create a file dothis-completion.bash:
#/usr/bin/env bash
complete -W "now tomorrow never" dothis
Run . ./dothis-completion.bash, and now pressing Tab will produce:
$ dothis <tab><tab>
never now tomorrow
$ dothis n<tab><tab>
never now
The -W flag specifies to take a word list. -F func — call a function and use its output as the completion list. -C cmd — same, but execute a command.
-A action — autocomplete with:
- alias aliases (= -a).
- arrayvar array variable names.
- binding readline bindings.
- builtin builtin command names (= -b).
- command command names (= -c).
- directory directories (= -d).
- disabled disabled builtin commands.
- enabled enabled builtin commands.
- export exported variables (= -e).
- file files (= -f).
- function functions.
- group groups (= -g).
- helptopic built-in help topics.
- hostname hosts (host file is specified by the HOSTFILE variable).
- job jobs (= -j).
- keyword shell keywords (= -k).
- running running tasks.
- service services (?) (= -s).
- setopt valid arguments for the shell -o option.
- shopt options for shopt.
- signal signals.
- stopped stopped jobs.
- user users (logins) (= -u).
- variable variables.
For example, complete -A directory dothis will complete with directory names.
Dynamic completion
Let’s change the script:
#/usr/bin/env bash
_dothis_completions()
{
COMPREPLY+=("now")
COMPREPLY+=("tomorrow")
COMPREPLY+=("never")
}
complete -F _dothis_completions dothis
This produces the same result as the original version — three completion options. However, if we type dothis ne<tab><tab>, we get all three options instead of the expected single never.
Let’s fix this. In the function called for autocompletion, the following variables are available:
- COMP_WORDS array of words entered after the program name;
- COMP_CWORD index of the word in the previous array where the cursor currently is;
- COMP_LINE the current command line.
Additionally, the built-in compgen function, which accepts the same flags as complete, can produce a completion list filtered by the beginning of a word. For example, compgen -W "now tomorrow never" n outputs now and never.
Therefore, the basic functionality can be obtained like this:
#/usr/bin/env bash
_dothis_completions()
{
COMPREPLY=($(compgen -W "now tomorrow never" "${COMP_WORDS[1]}"))
}
complete -F _dothis_completions dothis
Example of completing the -u flag with user names:
_dothis_completions()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if [[ ${prev} == -u ]] ; then
COMPREPLY=( $(compgen -u -- ${cur}) )
return 0
fi
}
All variables available in autocompletion:
-
COMP_CWORDIndex of the current word in${COMP_WORDS} -
COMP_LINEThe entire command line -
COMP_POINTCursor position relative to the beginning of the command line. If the cursor is at the very end, this equals${#COMP_LINE}. -
COMP_WORDBREAKSSet of characters considered word delimiters for autocompletion (do not modify it — it’s a global variable!). -
COMP_WORDSArray of words from the current${COMP_LINE}. -
COMPREPLYArray of words for autocompletion — the output of the completion script.