I'm trying to setup autocompletion for a command, which takes only one parameter, a folder name,

In /secure/kernel_builds/, I have the three following subfolder:

3.5.6/ 3.6.2/ source/

Now I want auto completion, that lists all sub folder name possible, but not the one named source, right now I'm using a pretty stupid way to do it, by checking if the completion word is started with a number,

    case $COMP_CWORD in
            if [[ "${COMP_WORDS[COMP_CWORD]}" =~ ^[0-9] ]];then
                COMPREPLY=( /secure/kernel_builds/"${COMP_WORDS[COMP_CWORD]}"* )
                COMPREPLY=( /secure/kernel_builds/"${COMP_WORDS[COMP_CWORD]}"[0-9]*/ )
            COMPREPLY=( "${COMPREPLY[@]#/secure/kernel_builds/}" )
            COMPREPLY=( "${COMPREPLY[@]%/}" )

Is there a better way of doing so?


The compgen builtin has a -X argument for this very purpose:

-X filterpat
    filterpat is a pattern as used for filename expansion. It is applied to the list of 
    possible completions generated by the preceding options and arguments, and each 
    completion matching filterpat is removed from the list. A leading ! in filterpat 
    negates the pattern; in this case, any completion not matching filterpat is removed.

So you could probably just do something like:

_avail_kernel_builds() {
    case $COMP_CWORD in
        1) COMPREPLY=( $(cd /secure/kernel_builds; compgen -d -X "source") ) ;;

So compgen -d says "list the folders in the current directory", and -X "source" says "...but filter out anything named "source".


You can check in a loop for the strings you (don't) want:

declare -a accept
declare -a reject
for s in "${COMPREPLY[@]}"; do
    if [[ "$s" =~ want ]]; then
        accept=( "${accept[@]}" "$s" )
        reject=( "${reject[@]}" "$s" )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.