If you’re getting the error:

-sh: <( compgen -f -X -- 'b' ): No such file or directory

when you’re trying to invoke filename completion, for example like this:

bjb@edouard:/etc$ ls b<tab>

where you typed a b and then tab, to find all the directory entries in /etc that start with b, then you might have the posix option set on your shell while using an old version of bash_completion package. The version that gave me grief was 20080705. Another machine has version 1:1.2-3 and it doesn’t suffer from this problem.

You can check by showing the contents of $SHELLOPTS:


(And getting the package version number: apt-cache policy bash_completion.)

If the contents of the SHELLOPT shell variable includes the posix keyword, then you will need to disable posix because the shell completion implementation in bash-completion 20080705 doesn’t seem to be posix compliant.

set +o posix

will turn OFF posix mode, and

set -o posix

will turn ON posix mode.

So to make command line completion work, I had to give the command set +o posix CORRECTED 2010-12-16

Figuring this out introduced me to an interesting shell construct that I hadn’t seen before. In the old version of /etc/bash_completion, in function _filedir, you see this:

        local IFS=$'\t\n' xspec

        _expand || 0

        local toks=( ) tmp
        while read -r tmp; do
                [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp
        done < <( compgen -d -- "$(quote_readline "$cur")" )

        if [[ "$1" != -d ]]; then
                while read -r tmp; do
                        [[ -n $tmp ]] && toks[${#toks[@]}]=$tmp
                done < <( compgen -f -X "$xspec" -- "$(quote_readline "$cur")" )

        COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" )

It is the <( some command with output to stdout ) construct that I hadn’t seen before. It represents “process substitution” and the man page says it “is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files. It takes the form of <( list ) or >( list ). The process list is run with its input or output connected to a FIFO or some file in /dev/fd. The name of this file is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list.”

And also I relearned about the declare -f which will show you all the function definitions your shell currently knows about.