Globbing with glob and rglob

pathlib · Practical · 9 min

Collecting inputs like 'every .py file in the project' is a one-liner with glob.

p.glob(pattern) yields paths below p that match a shell-style pattern:

  • * matches any characters within one path component
  • ? matches one character; [abc] a character set
  • ** matches any number of directories, including none

So p.glob("*.csv") searches one level, p.glob("**/*.csv") the whole tree, and p.rglob("*.csv") is shorthand for the latter. Results come in arbitrary order; sort them for stable output.

Details worth knowing:

  • Hidden files (starting with .) are matched by *, unlike in most shells.
  • Matching follows the platform's case rules by default; pass case_sensitive=True/False (3.12+) to override.
  • In 3.13, a pattern ending in ** yields both files and directories; earlier versions yielded only directories. Add /* or a suffix pattern if you want files only.
  • glob returns a generator; wrap in list() or sorted() to reuse the results.
  • Symlinked directories are not followed by ** unless you pass recurse_symlinks=True (3.13).

To exclude directories such as .git or node_modules, filter the results (".git" not in p.parts), or use Path.walk() where you can prune whole subtrees for speed.

Example

from pathlib import Path

for f in ["src/app.py", "src/util/io.py", "src/util/README.md",
          "tests/test_app.py", ".venv/lib/x.py"]:
    p = Path(f)
    p.parent.mkdir(parents=True, exist_ok=True)
    p.touch()

root = Path(".")
print(sorted(map(str, root.glob("src/*.py"))))   # ['src/app.py']
py = sorted(str(p) for p in root.rglob("*.py") if ".venv" not in p.parts)
print(py)    # ['src/app.py', 'src/util/io.py', 'tests/test_app.py']
print(sorted(p.name for p in root.glob("**/test_*.py")))  # ['test_app.py']
print(len(list(root.glob("src/util/*.MD", case_sensitive=False))))  # 1

Remember

  • glob('*.ext') searches one level; rglob('*.ext') or glob('**/*.ext') the whole tree
  • Results are unordered generators; sort and list them as needed
  • Filter by p.parts or use Path.walk to skip folders like .venv

Watch out for

  • Expecting glob('*.py') to search subdirectories; it only looks one level deep.

Check yourself

  1. Which call finds config.yaml files in a folder and all its subfolders?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/pathlib.html#pathlib.Path.glob