What Is Glob Pattern Matching and How Do Glob Wildcards Work?
Updated
Glob pattern matching is a way to select files by name using wildcards instead of listing them one by one. A pattern like *.jpg matches every file in the current directory ending in .jpg, which is why cp *.jpg ./thumbnails copies all JPEGs at once. You use globbing whenever you need to describe a set of files rather than name them individually — in shell commands, .gitignore rules, and build tool configs. The catch is that syntax varies by implementation, so a pattern that works in bash may behave differently in a JavaScript library.
Glob vs. regular expressions
Globbing and regular expressions both match patterns, but they solve different problems and are not interchangeable.
| Glob | Regular expression | |
|---|---|---|
| Primary target | File paths | Arbitrary text |
| Typical wildcard | * matches any string (including / in some cases) |
.* matches any string |
| Readability | Short, shell-friendly | More expressive, more verbose |
| Common tools | Shell, .gitignore, minimatch, Python glob |
grep, sed, most programming languages |
A glob pattern is not a regex. If you paste *.jpg into a regex engine, it means something else entirely. Keep the two mental models separate.
Core wildcards
The basic building blocks, as documented by minimatch (the library behind globster.xyz) and shell documentation:
?— matches a single character.*— matches any string./— the path separator. It is not a wildcard; it divides a path into segments.
So file?.txt matches file1.txt and fileA.txt but not file10.txt. And *.txt matches notes.txt and report.txt in the current directory.
Advanced syntax
Beyond the basics, minimatch supports several features that cover most real-world needs.
Globstar **
** matches all files and zero or more directories and subdirectories. If followed by /, it matches only directories and subdirectories.
Important constraint: to behave that way, ** must be the only thing inside its path segment. A pattern like /myapp/**.js will not work as a recursive match — the ** is glued to .js and loses its special meaning.
Brace expansion {a,b}
An expression inside curly braces expands into multiple patterns, and the final result is the union of all of them:
**/*.{b,c}expands into**/*.band**/*.c.- Brace sets like
**/{a..c}expand into**/a,**/b, and**/c.
Extended glob matching (extglob)
These operators come from the extended glob feature and give you regex-like control:
?(a|b)— matches zero or one occurrence.*(a|b)— matches zero or more occurrences.+(a|b)— matches one or more occurrences.@(a|b)— matches exactly one occurrence.!(a|b)— matches anything except the listed alternatives.
Where globbing is used
Globbing started in Unix and is now everywhere:
- Shell commands —
cp *.jpg ./thumbnails,rm build/*.log. - Git —
.gitignorepatterns exclude files and folders from version control. - Build and tooling configs — selecting source files, test files, or assets.
- Programming languages — JavaScript (
minimatch,micromatch,extglob), Python (globmodule), and Linux system globbing all implement their own versions.
Syntax varies by implementation
This is the most common source of confusion. The same pattern can mean different things depending on the engine:
- minimatch / micromatch (JavaScript) — supports
?,*, brace expansion, extglob, and globstar as described above. - Python
glob— supports*,?, and[]character ranges, but not extglob. - Shell glob — behavior depends on the shell and its options.
Before trusting a pattern, confirm which library or tool is evaluating it.
Debugging a pattern that doesn't match
When a glob fails, the fastest fix is to test it against a real file tree and see which files light up. globster.xyz is built for exactly this: you type a pattern into the input field and matched files are highlighted in blue in a directory tree, using minimatch 3.0.4 to evaluate the pattern. It also ships with an examples section you can learn from.
A practical workflow:
- Start with the simplest pattern that should match (
*.js). - Add one feature at a time (
**/*.js, then**/*.{js,ts}). - Watch which files highlight after each change.
- If
**stops working, check whether it is alone in its path segment.
That last point trips up more people than any other glob rule — a recursive match silently degrades into a literal one when ** is combined with other characters in the same segment.