Python fnmatch — Core Concepts
What fnmatch does
The fnmatch module provides Unix shell-style wildcard matching for strings — primarily filenames. It’s simpler than regular expressions and covers the common case of “find files matching a pattern.”
Pattern syntax
| Pattern | Meaning | Example match |
|---|---|---|
* | Any number of characters (including zero) | *.py → app.py, test.py |
? | Exactly one character | data_?.csv → data_A.csv, not data_AB.csv |
[seq] | Any one character in seq | file[123].txt → file1.txt, file2.txt |
[!seq] | Any one character NOT in seq | log[!0-9].txt → logA.txt, not log5.txt |
The * wildcard does not match path separators — *.py won’t match subdir/app.py. For recursive path matching, use pathlib.Path.glob() or the glob module.
The four functions
fnmatch.fnmatch(filename, pattern)
The primary function. Returns True if the filename matches the pattern. On Windows, matching is case-insensitive; on Unix, it’s case-sensitive.
import fnmatch
fnmatch.fnmatch("report_2024.csv", "report_*.csv") # True
fnmatch.fnmatch("image.PNG", "*.png") # True on Windows, False on Linux
fnmatch.fnmatchcase(filename, pattern)
Always case-sensitive, regardless of platform. Use this when you need consistent behavior:
fnmatch.fnmatchcase("image.PNG", "*.png") # False everywhere
fnmatch.fnmatchcase("image.png", "*.png") # True everywhere
fnmatch.filter(names, pattern)
Filters a list of names, returning only those that match. More efficient than calling fnmatch() in a loop because it pre-compiles the pattern:
files = ["app.py", "test.py", "README.md", "config.yaml", "utils.py"]
python_files = fnmatch.filter(files, "*.py")
# ['app.py', 'test.py', 'utils.py']
fnmatch.translate(pattern)
Converts a fnmatch pattern to a regular expression string. Useful when you need the pattern matching elsewhere:
fnmatch.translate("*.py")
# '(?s:.*\\.py)\\Z'
Practical use cases
Filtering directory listings
import os, fnmatch
for name in os.listdir("data/"):
if fnmatch.fnmatch(name, "*.csv"):
print(f"Processing {name}")
Multi-pattern matching
fnmatch doesn’t support OR patterns natively, but you can combine with any():
patterns = ["*.py", "*.js", "*.ts"]
source_files = [f for f in all_files if any(fnmatch.fnmatch(f, p) for p in patterns)]
Configuration-driven file selection
IGNORE_PATTERNS = ["*.pyc", "__pycache__", "*.egg-info", ".git"]
def should_include(filename):
return not any(fnmatch.fnmatch(filename, pat) for pat in IGNORE_PATTERNS)
fnmatch vs. glob vs. regex
| Feature | fnmatch | glob | regex |
|---|---|---|---|
| Matches filenames | ✅ | ✅ | ✅ |
| Traverses directories | ❌ | ✅ | ❌ |
| Recursive matching | ❌ | ✅ (**) | ✅ |
| Pattern complexity | Low | Low | High |
| Learning curve | Minimal | Minimal | Steep |
Use fnmatch when you already have a list of names and need to filter them. Use glob when you want to find files on disk. Use regex when wildcard patterns aren’t expressive enough.
Common misconception
fnmatch patterns look like glob patterns but they only match against a single filename component — they don’t understand directory paths. fnmatch.fnmatch("src/app.py", "*.py") returns True because * matches everything including /. This can surprise you if you expect * to stop at directory separators like glob does.
One thing to remember
fnmatch is the sweet spot between “check if a string ends with .py” and full regular expressions — readable patterns for filename matching, with filter() for efficient batch operations.
See Also
- Python Atexit How Python's atexit module lets your program clean up after itself right before it shuts down.
- Python Bisect Sorted Lists How Python's bisect module finds things in sorted lists the way you'd find a word in a dictionary — by jumping to the middle.
- Python Contextlib How Python's contextlib module makes the 'with' statement work for anything, not just files.
- Python Copy Module Why copying data in Python isn't as simple as it sounds, and how the copy module prevents sneaky bugs.
- Python Dataclass Field Metadata How Python dataclass fields can carry hidden notes — like sticky notes on a filing cabinet that tools read automatically.