Is there a way to customize "Programmable Completion" in the current session?

In the bash_completion mechanism it's the bash function _filedir_xspec() that is responsible for filename and dirname completions. This funtion can be found in the script /etc/bash_completion.

You can edit that function and add a line that contains your regex. For example use this function (it's a copy of the original function):

_filedir_xspec()
{
    local IFS cur xspec

    IFS=$'\n'
    COMPREPLY=()
    _get_comp_words_by_ref cur

    _expand || return 0

    # get first exclusion compspec that matches this command
    xspec=$( awk "/^complete[ \t]+.*[ \t]${1##*/}([ \t]|\$)/ { print \$0; exit }" \
        "$BASH_COMPLETION" )
    # prune to leave nothing but the -X spec
    xspec=${xspec#*-X }
    xspec=${xspec%% *}

    local -a toks
    local tmp

    toks=( ${toks[@]-} $(
        compgen -d -- "$(quote_readline "$cur")" | {
        while read -r tmp; do
            # see long TODO comment in _filedir() --David
            printf '%s\n' $tmp
        done
        }
        ))

    # Munge xspec to contain uppercase version too
    eval xspec="${xspec}"
    eval xspec="!*.txt" #<---- HERE add your regex, that's the only line changed
    local matchop=!
    if [[ $xspec == !* ]]; then
        xspec=${xspec#!}
        matchop=@
    fi
    [[ ${BASH_VERSINFO[0]} -ge 4 ]] && \
        xspec="$matchop($xspec|${xspec^^})" || \
        xspec="$matchop($xspec|$(printf %s $xspec | tr '[:lower:]' '[:upper:]'))"

    toks=( ${toks[@]-} $(
        eval compgen -f -X "!$xspec" -- "\$(quote_readline "\$cur")" | {
        while read -r tmp; do
            [ -n $tmp ] && printf '%s\n' $tmp
        done
        }
        ))
    [ ${#toks[@]} -ne 0 ] && _compopt_o_filenames
    COMPREPLY=( "${toks[@]}" )
}

Notice the new part at line 32:

eval xspec="!*.txt" 

This statement is later used in compgen to remove all entries, that do not match the regular expression. I wouldn't recommend to edit the file /etc/bash_completion. Instead make a new file with the content above and source the file if needed:

source /path/to/file

Now, all commands/applications in the shell, that where completed by the function _filedir_xspec(), complete now only with *.txt filenames.


You can also use this only for certain programs, or your custom script or command.

For showing only files that have the txt extension in the suggestion, simply write a shell script and source in the current session:

# Autocomplete file /path/to/file/sample-completion.sh
# for the command `sample`
_sample(){
   COMPREPLY=($(compgen -f -X "!.*[.][tT][xX][tT]$" -- "$2"))
}

complete -F _sample sample

And source it by calling:

$ source /path/to/file/sample-completion.sh

In this code, $2 is the current word being completed. The -- "$2" part makes compgen filter out only the suggestions that contain the current word being completed and put it into COMPREPLY. Also, the -f option tells compgen to only look for files in the current directory. Last but not least the -X option is a filter pattern (look here) that excludes matching file names. The ! in the beginning of pattern negates this behavior. As a result, only the files with .txt extension will be shown. The $ sign at the end of the regex looks for matches that end with given pattern. The [.] means it will look for a literal dot, not just any character - which is the default meaning of a dot in regex. The [tT][xX][tT] part means the pattern will match all these situations: "txt, txT, tXt, tXT, Txt, TxT, TXT, TXt".