Glob Patterns: Complete Syntax Reference with Examples
Complete reference for glob pattern syntax - wildcards, character classes, brace expansion, and shell-specific features. Every pattern explained with examples.
- tags
- #Shell #Unix #Patterns #Glob #Cli #Developer-Tools #Terminal #Bash #Zsh #Reference #Syntax #Gitignore #File-Matching
- categories
- Developer-Tools Tutorials
- published
- reading time
- 9 minutes
📚 Series: Glob Patterns
- Glob Patterns: The Invisible Abstraction Everyone Uses But Nobody Learns
- Glob Patterns: Complete Syntax Reference with Examples (current)
In
Part 1
, we covered why glob patterns are everywhere but never taught explicitly. This is the reference you wish existed when you first encountered **/*.js or tried to write a .gitignore.
This is your glob syntax cheat sheet. Bookmark it. Use it when debugging patterns. Reference it when writing configs.
Table of Contents
- The Core Patterns (Universal)
-
*,**,?,[...],[!...] - Brace Expansion
-
{a,b},{1..5} - Extended Globs
-
?(pattern),*(pattern),+(pattern),@(a|b),!(pattern) - Dotfile Handling - Shell differences for hidden files
- Tool-Specific Behavior - .gitignore, rsync, find
- Common Edge Cases and Gotchas - What breaks and why
- Quick Reference Table - All patterns at a glance
- Practice Exercises - Test your understanding
The Core Patterns (Universal)
These patterns work in all shells and most tools (git, rsync, build tools, etc.).
* - Match Any Characters (Except Path Separator)
Matches zero or more characters, but does not cross directory boundaries.
| |
Important edge case:
| |
** - Match Directories Recursively
Matches any number of directories (including zero).
| |
Shell-specific behavior:
| |
? - Match Exactly One Character
Matches any single character (except path separator).
| |
[...] - Match One Character From Set
Matches exactly one character from the bracketed set.
| |
Common ranges:
[0-9]- Digits[a-z]- Lowercase letters[A-Z]- Uppercase letters[a-zA-Z]- All letters[a-zA-Z0-9]- Alphanumeric
[!...] - Match One Character NOT in Set
Negation - matches any character except those in the brackets.
| |
Note: Some tools use [^...] instead of [!...] for negation (both work in most shells).
Brace Expansion (Shell Feature)
Not strictly glob, but commonly used with globs. Expands to multiple patterns.
| |
Important: Brace expansion happens before globbing. The shell expands {a,b} first, then applies glob patterns to each result.
Extended Globs (Shell-Specific)
Available in bash (with shopt -s extglob) and zsh (enabled by default).
?(pattern) - Match Zero or One Occurrence
| |
*(pattern) - Match Zero or More Occurrences
| |
+(pattern) - Match One or More Occurrences
| |
@(pattern|pattern) - Match Exactly One Pattern
| |
!(pattern) - Match Anything Except Pattern
| |
Enable in bash:
| |
Available by default in zsh.
Dotfile Handling (Hidden Files)
Different shells have different defaults for matching dotfiles (files starting with .).
| |
In .gitignore:
# Matches hidden files explicitly
.*
# Exclude . and .. pattern
.*
!.gitignore
# Pattern without leading . matches non-hidden
*.log # Doesn't match .hidden.log
Tool-Specific Behavior
.gitignore Patterns
Git has its own glob interpretation with special rules:
# Pattern without / matches anywhere in tree
node_modules
# Matches: node_modules/, src/node_modules/, lib/vendor/node_modules/
# Leading / anchors to repository root
/build
# Matches: build/ (in root only)
# Doesn't match: src/build/, lib/build/
# Trailing / matches directories only
logs/
# Matches: logs/ (directory)
# Doesn't match: logs (file)
# ** for recursive matching
dist/**/*.map
# Matches: dist/app.js.map, dist/src/lib/utils.js.map
# ! for negation (must come after matching pattern)
*.log
!important.log
# Ignores all .log files except important.log
# ** in middle of pattern
src/**/test/*.js
# Matches: src/test/app.test.js, src/lib/test/utils.test.js
Pattern order matters in .gitignore:
# Wrong - negation before match
!important.log
*.log
# Result: All .log files ignored (including important.log)
# Correct - negation after match
*.log
!important.log
# Result: All .log files ignored except important.log
rsync Patterns
| |
find Command (Not Glob, But Similar)
| |
Common Edge Cases and Gotchas
1. Empty Directories
| |
2. Literal Special Characters
| |
3. Case Sensitivity
| |
4. Null Glob (No Matches)
| |
Quick Reference Table
| Pattern | Meaning | Example | Matches |
|---|---|---|---|
* | Any characters (no /) | *.js | file.js, not src/file.js |
** | Recursive directories | src/**/*.js | src/a/b/c.js |
? | Exactly one character | file?.js | file1.js, fileA.js |
[abc] | One char from set | [0-9].txt | 5.txt, 9.txt |
[!abc] | One char NOT in set | [!.]*.txt | file.txt, not .hidden.txt |
{a,b} | Alternatives (brace) | *.{js,ts} | app.js, app.ts |
?(pattern) | Zero or one | file?(s).txt | file.txt, files.txt |
*(pattern) | Zero or more | file*([0-9]).txt | file.txt, file123.txt |
+(pattern) | One or more | file+([0-9]).txt | file1.txt, not file.txt |
@(a|b) | Exactly one of | @(LICENSE|README) | LICENSE, README |
!(pattern) | Anything except | !(*.tmp) | file.js, not temp.tmp |
Practice Exercises
Test your understanding with these scenarios:
Exercise 1: Write patterns for:
| |
Exercise 2: What do these match?
| |
What’s Next
Now that you know the complete syntax, the next parts cover practical applications:
- Part 3: Mastering .gitignore patterns with real-world examples
- Part 4: Glob vs regex - when to use each and how they differ
- Part 5: Advanced patterns - negation strategies, performance, tool-specific extensions
Bookmark this page. You’ll reference it when debugging patterns, writing configs, or explaining glob to teammates.
📚 Series: Glob Patterns
- Glob Patterns: The Invisible Abstraction Everyone Uses But Nobody Learns
- Glob Patterns: Complete Syntax Reference with Examples (current)