问题
I've been trying to add bash completion support to a command line program I've been using lately, but it seems that I've hit a wall.
Here are the commands and subcommands I'd like to auto-complete
Main command is
foo
, autocompletion should be performed for the subcommandsversion
,process
, andhelp
. Further autcompletion depends on the subcommand.If the user enters
-
after the main command, autocompletion performs completion for these word:--activate
or--deactivate
If the user enters
--deactivate
, it should perform autocompletion of a bash command output (let's sayls
).
version
: no autocompletion performedprocess
: autocompletion defaults to listing directories (current and parent included)- If the user enters
-
, autocompletion performs completion for these words:--color
,--verbose
and then stops afterward
- If the user enters
If the user enters
help
, autocompletion is for the other subcommands (process
orversion
).
Here's my current implementation of the autocomplete script (which is failing badly):
_foo() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
words=("${COMP_WORDS[@]}")
cword=$COMP_WORD
opts="process version help"
case "$prev" in
-*)
local subopts="--activate --deactivate"
COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
case "$cur" in
--deactivate)
COMPREPLY=( $(ls) )
;;
esac
;;
version)
COMPREPLY=()
;;
process)
case "$cur" in
-*)
local subopts="--color --verbose"
COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
;;
*)
COMPREPLY=( $(compgen -A directory))
;;
esac
;;
help)
COMPREPLY=( $(compgen -W "process version" -- ${cur}) )
;;
esac
}
complete -F _foo foo
You can probably see that Bash is not my main forte as well. I was thinking of writing separate bash functions for each subcommands, but I don't know how to do it at the moment. If you have suggestions on how to implement this as well, I would really appreciate it.
Thanks!
回答1:
In case of the possible subcommands on first level it's a bit unclear for me.
Should it be possible to enter foo --activate
or foo - --activate
? The latter looks somehow strange but fits more likely to your given code.
The first sounds more reasonable, but would imply to have --activate
etc. as kind of global parameter that is to be treated on the same level like your subcommands.
Nevertheless you missed the default, when you haven't entered anything yet. Try the following code:
_foo() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
words=("${COMP_WORDS[@]}")
cword=$COMP_CWORD
opts="process version help"
case "$prev" in
-*)
local subopts="--activate --deactivate"
COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
case "$cur" in
--deactivate)
COMPREPLY=( $(ls) )
;;
esac
return 0
;;
version)
COMPREPLY=()
return 0
;;
process)
case "$cur" in
-*)
local subopts="--color --verbose"
COMPREPLY=( $(compgen -W "${subopts}" -- ${cur}) )
;;
*)
COMPREPLY=( $(compgen -A directory))
;;
esac
return 0
;;
help)
COMPREPLY=( $(compgen -W "process version" -- ${cur}) )
return 0
;;
esac
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
return 0
}
complete -F _foo foo
which is basically the same as yours but: At the bottom, set COMPREPLY to your first level subcommands so they get completed. In case of having entered a subcommand, you should return (0) to not reach the final statement.
The example given will work with foo - --activate
which may not what you wanted.
So if you wanted to enter foo --activate
change the according lines to
case "$prev" in
--activate)
COMPREPLY=()
return 0
;;
--deactivate)
COMPREPLY=( $(compgen -W "$(ls)" -- ${cur}) )
return 0
;;
version)
...
来源:https://stackoverflow.com/questions/9340045/nested-bash-autocompletion-script