I'm writing a custom completion function for a bash script (this script is for activating deactivating nginx configuration files). I'm trying to have a different behavior if the completed word starts with --, is empty, or starts with something else. Typically, if I write command --<TAB>, I should have --help --someoptions suggested, whereas if I type command <TAB> then I should have the content of a specific directory, matching a specific regex, shown as completion suggestions.
Here is the code of my completion function:
#!/bin/bash
source "./common"
_comp_nginx_conf(){
local IFS=$' '
local cur long_help conf_files new_help
cur=
long_help=( "help" "test" "testmode" "deactivate" "activate" )
# for correct completion, check if test mode is in the options
for arg in "${COMP_WORDS[@]}"; do
if [[ "$arg" == "--test" || "$arg" == "-t" ]]; then
TEST_MODE=true
fi
done
[[ $TEST_MODE ]] && cd "$TEST_PATH" &> /dev/null || cd "$PROD_PATH" &> /dev/null
conf_files=$(ls -b *(.conf|.conf.incative) 2> /dev/null)
new_help=()
COMPREPLY=()
cur="$2"
if [[ $cur =~ "--".* ]]; then
COMPREPLY=( $(compgen -W "${long_help[*]}" -P "--" -- $cur) )
else
COMPREPLY=( $(compgen -W "${conf_files[*]}" -- $cur) )
fi
return 0
} &&
complete -F _comp_nginx_conf nginx-conf
The issue here is, when I type command --<TAB> it should offer --help --testmode --deactivate --activate and when I type command <TAB> it should offer test.conf test2.conf.inactive and all the conf files in $TEST_PATH, but instead it still offers --someoptions.
I don't understand why I get this result, so this is where I need help, how to achieve the behavior I want and why don't I get it with the code I wrote?
I think I find your function too complicated.
*(...)is an extended glob. For the-P --you have to${cur%--}remove the dashes, otherwise they won't match. And I do not get the "TEST_MODE" - why would you want confuse users by changing directory in completion function! I useset -xfor testing. Also function definition always succeeds, why&&of it.Overall, why care at all, compgen will just return nothing:
If you want to complete files from some directory, change the directory in the subshell. I would be very confused if my PWD would change when executing completion.
Check your scripts with shellcheck. Prefer
ifover&& ||.