Multi Level Bash Completion
I currently have a Bash completion file which completes a single parameter from a list of allowed commands for a script called pbt
. This is the working Bash completion file:
_pbt_complete()
{
local cur goals
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
goals='asadmin clean deploy'
cur=`echo $cur`
COMPREPLY=($(compgen -W "${goals}" ${cur}))
}
complete -F _pbt_complete pbt
So if I call
pbt <tab>
Bash completes to all allowed commands (asadmin
, clean
, deploy
), which is okay. Now I want to add a second level to the completion. So for example if I type
pbt asadmin <tab>
I want it to complete only options that are available inside the asadmin
"environment" (which I'll also define inside the Bash completion file). For example p开发者_StackOverflow社区bt asadmin [start-domain|stop-domain]
. But if I type
pbt deploy <tab>
It should complete to another set of options. For example, pbt deploy [all|current]
. So the options for the second command should always depend on the first command.
How can I do that in the completion file?
Thanks to mkb's comment, I looked into the p4
example, which was—unlike the Git example—simple enough for me to adapt to my case. Here is the working version which does exactly what I asked for:
have pbt &&
_pbt_complete()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ]; then
COMPREPLY=( $(compgen -W "asadmin deploy" -- $cur) )
elif [ $COMP_CWORD -eq 2 ]; then
case "$prev" in
"asadmin")
COMPREPLY=( $(compgen -W "start-domain stop-domain" -- $cur) )
;;
"deploy")
COMPREPLY=( $(compgen -W "all current" -- $cur) )
;;
*)
;;
esac
fi
return 0
} &&
complete -F _pbt_complete pbt
Btw, here are two useful tips on better tab completion:
- use
bind 'set show-all-if-ambiguous on'
# this makes only one Tab necessary to show possible completions - use this Fish-like package for Bash that automatically shows possibles and history as you type: https://superuser.com/a/1644033/388883 (called ble.sh)
Here is more info on how to use the complete
command to adjust tab completetion. This page has an incredible breakdown, and discusses known application using "cobra (Golang), click (Python) and clap (Rust) tools"
https://echorand.me/posts/linux_shell_autocompletion/ (and how Git uses Compgen)
Here is a link the the GH repo for Debian bash-completion
: https://github.com/scop/bash-completion
Q. What is the search order for the completion file of each target command?
A. The completion files of commands are looked up by the shell function __load_completion. Here, the search order in bash-completion >= 2.12 is explained.
- BASH_COMPLETION_USER_DIR. The subdirectory completions of each paths in BASH_COMPLETION_USER_DIR separated by colons is considered for a completion directory.
- The location of the main bash_completion file. The subdirectory completions in the same directory as bash_completion is considered.
- The location of the target command. When the real location of the command is in the directory /bin or /sbin, the directory /share/bash-completion/completions is considered.
- XDG_DATA_DIRS (or the system directories /usr/local/share:/usr/share if empty). The subdirectory bash-completion/completions of each paths in XDG_DATA_DIRS separated by colons is considered.
The completion files of the name or .bash, where is the name of the target command, are searched in the above completion directories in order. The file that is found first is used. When no completion file is found in any completion directories in this process, the completion files of the name _ is next searched in the completion directories in order.
You may want to look at how the completion for git is done, as an example. (This takes 2257 lines of function definitions and additional 14 variables in my bash setup.)
精彩评论