What expands to all files in current directory recursively?

bash, glob, shell, shopt, wildcard

Solution

This will work in Bash 4:

ls -l {,**/}*.ext

In order for the double-asterisk glob to work, the `globstar` option needs to be set (default: on):

shopt -s globstar

From `man bash`:

    globstar
                  If set, the pattern ** used in a filename expansion con‐
                  text will match a files and zero or more directories and
                  subdirectories.  If the pattern is followed by a /, only
                  directories and subdirectories match.

Now I'm wondering if there might have once been a bug in globstar processing, because now using simply `ls **/*.ext` I'm getting correct results.

Regardless, I looked at the analysis kenorb did using the VLC repository and found some problems with that analysis and in my answer immediately above:

The comparisons to the output of the `find` command are invalid since specifying `-type f` doesn't include other file types (directories in particular) and the `ls` commands listed likely do. Also, one of the commands listed, `ls -1 {,**/}*.*` - which would seem to be based on mine above, only outputs names that include a dot for those files that are in subdirectories. The OP's question and my answer include a dot since what is being sought is files with a specific extension.

Most importantly, however, is that there is a special issue using the `ls` command with the globstar pattern `**`. Many duplicates arise since the pattern is expanded by Bash to all file names (and directory names) in the tree being examined. Subsequent to the expansion the `ls` command lists each of them and their contents if they are directories.

Example:

In our current directory is the subdirectory `A` and its contents:

A
└── AB
    └── ABC
        ├── ABC1
        ├── ABC2
        └── ABCD
            └── ABCD1

In that tree, `**` expands to "A A/AB A/AB/ABC A/AB/ABC/ABC1 A/AB/ABC/ABC2 A/AB/ABC/ABCD A/AB/ABC/ABCD/ABCD1" (7 entries). If you do `echo **` that's the exact output you'd get and each entry is represented once. However, if you do `ls **` it's going to output a listing of each of those entries. So essentially it does `ls A` followed by `ls A/AB`, etc., so `A/AB` gets shown twice. Also, `ls` is going to set each subdirectory's output apart:

...
<blank line>
directory name:
content-item
content-item

So using `wc -l` counts all those blank lines and directory name section headings which throws off the count even farther.

This a yet another reason why you should not parse `ls`.

As a result of this further analysis, I recommend not using the globstar pattern in any circumstance other than iterating over a tree of files in this manner:

for entry in **
do
    something "$entry"
done

As a final comparison, I used a Bash source repository I had handy and did this:

shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .

I used `tr` to change spaces to newlines which is only valid here since no names include spaces. I used `sed` to remove the leading `./` from each line of output from `find`. I sorted the output of `find` since it is normally unsorted and Bash's expansion of globs is already sorted. As you can see, the only output from `diff` was the current directory `.` output by `find`. When I did `ls ** | wc -l` the output had almost twice as many lines.

Problem

I know `**/*.ext` expands to all files in all subdirectories matching `*.ext`, but what is a similar expansion that includes all such files in the current directory as well?

Original source

Related problems