Finding Files with glob & fnmatch

The glob module finds real files on disk that match a wildcard pattern, while fnmatch tests whether a filename string matches such a pattern — together they make file searching simple and readable.

Learn Finding Files with glob & fnmatch in our free Python course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Instead of manually walking directories, you write a pattern like *.txt or **/*.py and Python hands you the matching paths. It's one of the most practical everyday skills in the standard library.

We create a few files in a temp directory so the demo is deterministic, then match them. * matches any run of characters, ? matches exactly one. Always sorted() the results for a stable order:

To search inside subdirectories, use ** with recursive=True . Even nicer is pathlib : Path.glob for one level, Path.rglob for a full recursive walk — and it yields Path objects with a handy .name :

fnmatch tests a string against a glob-style pattern — no filesystem access. Perfect for filtering a list of names you already have. fnmatchcase is always case-sensitive, regardless of operating system:

Replace each ___ so the code finds all PNG files in the temp directory and counts them.

A leading * does not match files starting with a dot (like .env ). To include them, match the dot explicitly with a pattern like .* .

Recursively find every .log file with rglob , then use fnmatch to keep only the ones whose name starts with app .

Lesson complete — you can find any file by pattern!

You can match files with * , ? , and [ ] , search subfolders with recursive ** and rglob , filter name strings with fnmatch , and you always sort() for deterministic results.

🚀 Up next: shutil — copy, move, archive, and delete files and whole folders.

Practice quiz

In a glob pattern, what does * match?

  • Exactly one character
  • Only digits
  • Any number of characters (including none) within a path segment
  • Only the dot in a filename

Answer: Any number of characters (including none) within a path segment. * matches any run of characters within a single path segment; ? matches exactly one character.

What does ? match in a glob pattern?

  • Exactly one character
  • Any number of characters
  • A literal question mark
  • A directory boundary

Answer: Exactly one character. ? matches exactly one character, so ?.txt matches a.txt and b.txt but not data1.txt.

How do you search inside subfolders with glob.glob?

  • Use * at the end
  • Use fnmatch instead
  • Use a trailing slash
  • Use ** with recursive=True

Answer: Use ** with recursive=True. Recursive search needs the ** wildcard together with recursive=True.

Without recursive=True, how does ** behave in glob.glob?

  • It raises an error
  • It behaves like a single *
  • It matches hidden files
  • It matches nothing

Answer: It behaves like a single *. ** only crosses folder boundaries when recursive=True; otherwise it acts like a single *.

When would you use fnmatch instead of glob?

  • When you already have a list of name strings to filter, with no disk access
  • When you want to touch the filesystem
  • When you need to create files
  • When matching binary data

Answer: When you already have a list of name strings to filter, with no disk access. fnmatch just tests strings against a pattern without filesystem access — ideal for filtering an existing list.

What does fnmatch.fnmatchcase("Photo.JPG", "*.jpg") return?

  • True
  • An error
  • False
  • None

Answer: False. fnmatchcase is always case-sensitive, so uppercase .JPG does not match lowercase *.jpg — it returns False.

What does fnmatch.fnmatchcase("Photo.JPG", "*.JPG") return?

  • False
  • True
  • An error
  • None

Answer: True. Case matches exactly here, so fnmatchcase returns True.

In what order does glob.glob return its results?

  • Always alphabetical
  • Reverse alphabetical
  • By file size
  • Arbitrary, filesystem-dependent order

Answer: Arbitrary, filesystem-dependent order. glob returns paths in arbitrary order; wrap it in sorted() for deterministic output.

How is fnmatch.fnmatchcase different from plain fnmatch.fnmatch?

  • fnmatchcase ignores case
  • fnmatchcase is always case-sensitive regardless of OS
  • fnmatchcase touches the disk
  • There is no difference

Answer: fnmatchcase is always case-sensitive regardless of OS. Plain fnmatch follows OS case rules; fnmatchcase is always case-sensitive everywhere.

Does a leading * match hidden dotfiles like .env?

  • Yes, always
  • Only with recursive=True
  • No — you must match the dot explicitly
  • Only on Windows

Answer: No — you must match the dot explicitly. A leading * does not match files starting with a dot; match the dot explicitly (e.g. .*) to include them.