如何解决Bash可编程补全处理短选项-...与长选项--...的异常问题
问题根因
- 短/长选项触发
compgen参数解析异常:compgen默认会将所有-开头的输入识别为自身的选项,当匹配前缀是--或者--xxx时,会被误判为compgen的选项终止符或非法选项,直接导致补全内容截断、参数报错。 - 无匹配列表时触发全局默认补全:当当前输入路径没有对应层级的
xxx_args补全定义时(比如已经输入完-a无下一级补全项),间接取值得到的补全列表为空,compgen在-W参数为空时会自动 fallback 到系统全局的命令、别名、文件补全,导致输出多余内容。
修复方案
仅需要修改补全函数末尾的compgen调用逻辑,增加空列表判断和参数分隔符即可,完整修改后的补全脚本如下:
#!/bin/bash # # bash_completion_test # echo 'Begin bash_completion_test...' # test definitions _args=(add list remove) list_args=(student teacher) list_student_args=(age grade name) list_student_grade_args=(-a -o --another --option) list_teacher_args=(name) # # Generic hierarchical completion # function generic_hierarchical_completion_test() { local arguments word_list_ptr word DEBUG candidate_list log='bash_completion_test.log' echo -n '␃🖕' > $log # clear log file DEBUG= #true # set variable for debugging info in log file [[ $DEBUG ]] && echo -n > $log # Array of individual words in the current command line [[ $DEBUG ]] && echo "COMP_WORDS=${COMP_WORDS[@]}" >> $log # Second word to last word in the current command line arguments=("${COMP_WORDS[@]:1}") [[ $DEBUG ]] && echo "arguments=${#arguments[@]}:${arguments[@]}" >> $log # Remove last empty word from arguments [[ "${#COMP_WORDS[@]}" -gt 1 ]] && unset 'arguments[${#arguments[@]}-1]' [[ $DEBUG ]] && echo "arguments=${#arguments[@]}:${arguments[@]}" >> $log # Create word list pointer variable from arguments while replacing spaces with '_' IFS=_ word_list_ptr="${arguments[*]}_args[*]" unset IFS [[ $DEBUG ]] && echo "word_list_ptr=$word_list_ptr" >> $log [[ $DEBUG ]] && echo "word_list=${!word_list_ptr}" >> $log word=${COMP_WORDS[${COMP_CWORD}]} [[ $DEBUG ]] && echo "word=$word" >> $log # ========== 修复逻辑开始 ========== candidate_list="${!word_list_ptr}" # 无对应补全列表时直接返回空,避免触发默认全局补全 if [[ -z "$candidate_list" ]]; then COMPREPLY=() return 0 fi # 加--分隔compgen选项和匹配前缀,避免-开头的前缀被识别为compgen参数 COMPREPLY=( $( compgen -W "$candidate_list" -- "$word" ) ) # ========== 修复逻辑结束 ========== } complete -F generic_hierarchical_completion_test ct echo 'End bash_completion_test.'
修改后所有异常都会消除:--前缀补全不会被截断,输入完全匹配的选项后不会输出多余系统别名,也不会再触发compgen参数报错。
内容的提问来源于stack exchange,提问作者Gerold Broser
相关产品推荐
相关产品推荐

