Python Basics: Matching Filename Patterns with fnmatch
Imagine receiving a list of export filenames and needing only the daily sales reports. Python’s standard-library fnmatch module checks strings against shell-style patterns. It does not search your disk.
Use Python 3.12 or newer in Bash on Linux. Each example runs independently and creates no data files.
Filter a list of names
Save as demo_fnmatch_1.py:
import fnmatch
filenames = ["sales-01.csv", "notes.txt", "sales-02.csv", "sales-final.csv"]
daily_exports = fnmatch.filter(filenames, "sales-??.csv")
print(daily_exports)
print(fnmatch.fnmatch("notes.txt", "*.csv"))Run it from the directory where you saved it:
python3 demo_fnmatch_1.pyOutput:
['sales-01.csv', 'sales-02.csv']
False? matches one character; * matches any number, including zero. filter() returns matching names in input order. These patterns are not regular expressions: sales-??.csv also accepts sales-ab.csv.
Require digits or a literal question mark
Save as demo_fnmatch_2.py:
from fnmatch import fnmatchcase
pattern = "sales-[0-9][0-9].csv"
print("Digits:", fnmatchcase("sales-07.csv", pattern))
print("Letters:", fnmatchcase("sales-ab.csv", pattern))
print("Literal question mark:", fnmatchcase("draft?.txt", "draft[?].txt"))
print("Exclude zero:", fnmatchcase("part-3.txt", "part-[!0].txt"))Run it from the directory where you saved it:
python3 demo_fnmatch_2.pyOutput:
Digits: True
Letters: False
Literal question mark: True
Exclude zero: True[0-9] matches one ASCII digit, while [!0] matches one character other than 0. Wrap a wildcard in brackets to match it literally. Two digit positions check the shape of a name, not whether its number is a valid calendar day.
Choose case and path rules deliberately
Save as demo_fnmatch_3.py:
from fnmatch import fnmatchcase
filename = "REPORT.CSV"
print("Exact case:", fnmatchcase(filename, "*.csv"))
print("Normalized:", fnmatchcase(filename.casefold(), "*.csv"))
print("Nested path:", fnmatchcase("archive/report.csv", "*.csv"))
print("Hidden name:", fnmatchcase(".private.csv", "*.csv"))Run it from the directory where you saved it:
python3 demo_fnmatch_3.pyOutput:
Exact case: False
Normalized: True
Nested path: True
Hidden name: Truefnmatch() follows platform case normalization; fnmatchcase() always compares case-sensitively. Normalize both name and pattern when your rules ignore case. Slashes and leading dots have no special protection. Match a path’s basename and exclude hidden names separately when needed. For filesystem discovery, use glob or pathlib.
References
Acknowledgements
This post was created with assistance from AI.