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.