144

I'd like to write something like this:

$ ls **.py

in order to get all .py filenames, recursively walking a directory hierarchy.

Even if there are .py files to find, the shell (bash) gives this output:

ls: cannot access **.py: No such file or directory

Any way to do what I want?

EDIT: I'd like to specify that I'm not interested in the specific case of ls, but the question is about the glob syntax.

3 Answers 3

177

In order to do recursive globs in bash, you need the globstar feature from Bash version 4 or higher.

From the Bash documentation:

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

For your example pattern:

shopt -s globstar
ls -d -- **/*.py
7
  • 2
    I'd recommend also enabling nullglob Oct 4, 2012 at 16:50
  • 8
    @glennjackman But before enabling nullglob, I would strongly advise reading following warnings. Jun 19, 2013 at 21:53
  • 4
    ^ Warnings have moved here.
    – rgajrawala
    Nov 29, 2015 at 7:42
  • 4
    With bash 3.2, wc -l {**,.}/*.py works just fine
    – Raphael
    Feb 28, 2018 at 19:50
  • @Raphael I double checked the release notes and it definitely says that it was introduced in 4.0. Perhaps you distribution has backported a patch for it? IIRC RHEL 5 had backported some features. Also of note, it's been 9 years since bash 4 was released...
    – jordanm
    Feb 28, 2018 at 20:21
20
find . -name '*.py'

** doesn't do anything more than a single *, both operate in the current directory

3
  • Interesting. Though, I'm more focused on the glob syntax by itself, because I have to use it in a configuration file (include directive). I don't need a list of files.
    – Paolo
    Oct 4, 2012 at 15:48
  • 2
    @Doug O'Neal, that's no longer true. bash has now copied that zsh feature (though it adopted a syntax closer to that of ksh93 and like ksh, doesn't support zsh's globbing qualifiers yet which limits its usefulness) Oct 4, 2012 at 20:34
  • 1
    There are lots of things you can do with find if you don't have bash 4. Examples: yourcommand `find . -name '*.py'` (note the backticks); find . -name '*.py' -exec yourcommand {} \;.
    – Mars
    Oct 28, 2015 at 18:43
19

Since Bash 4 (also including zsh) a new globbing option (globstar) has been added which treats the pattern ** differently when it's set.

It is matching the wildcard pattern and returning the file and directory names that match then by replacing the wildcard pattern in the command with the matched items.

Normally when you use **, it works similar to *, but it's recurses all the directories recursively (like a loop).

To see if it's enabled, check it by shopt globstar (in scripting, use shopt -q globstar).

The example **.py would work only for the current directory, as it doesn't return list of directories which can be recurses, so that's why you need to use multiple directory-level wildcard **/*.py, so it can go deeper.

Look here for examples of finding files recursively.

1
  • 4
    Thanks! The globstar can be enabled by shopt -s globstar. Mar 24, 2021 at 14:24

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.