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?

2 Answers 2


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" )

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .