Glob#

Glob patterns are the simpler, older cousin of regex: a small pattern language for matching filenames. Used by the shell, .gitignore, rsync, find -name, build tools, and more.

Core Syntax#

A small alphabet, five or six metacharacters that cover nearly every filename-matching task. Glob trades regex’s expressive power for simpler reading and stricter path semantics; wildcards stop at directory separators unless the extended ** is enabled.

Pattern

Matches

*

any sequence of characters (excluding /)

?

a single character (excluding /)

[abc]

one of the characters

[a-z]

range

[!abc]

not one of (some shells use [^abc] instead)

**

any number of path segments (extended glob)

{a,b,c}

brace expansion, one of a, b, or c

  • * does not match path separators by default.

  • Hidden files (.foo) are usually not matched by * – enable dotglob / equivalent if needed.

Examples#

A handful of common patterns that show up across shells, build tools, ignore files, and find invocations. Each one is worth recognizing on sight; together they cover most of the patterns operators write in a typical week.

Pattern

Matches

*.txt

text files in the current directory

src/*.go

Go files directly in src/

src/**/*.go

Go files at any depth under src/

[Mm]akefile

Makefile or makefile

test_*.py

files starting with test_

*.{js,ts,jsx,tsx}

any of these extensions

!node_modules

negation in .gitignore

Glob vs. Regex#

The two pattern languages serve different jobs. Glob is for filenames, regex is for arbitrary text. Reading a glob pattern is easier; writing one keeps the operator out of escape-character traps that regex routinely sets. The list below codifies the dividing line.

  • Glob is much smaller; only *, ?, and character classes plus some extensions.

  • Glob is anchored to the whole path by default; regex is by default partial.

  • Glob has no quantifiers, alternation (without brace expansion), or groups.

  • Regex is more powerful and harder to read.

When matching filenames, glob is almost always the right tool.

Extended Glob (**)#

Recursive matching across path segments.

src/**/*.test.ts        # any depth under src/
**/node_modules         # any node_modules at any depth
docs/**/index.md        # any index.md anywhere under docs/

Most modern tools (npm scripts, Bazel, Bun, fast-glob, gitignore) support **. POSIX shells need shopt -s globstar (Bash) or setopt extendedglob (Zsh).

.gitignore Patterns#

The dialect every developer touches most often. Git’s ignore files extend plain glob with negation, directory-only matches, and anchoring rules that let one short file describe which files are tracked and which are not, across deeply nested trees.

Git’s pattern format extends glob with negation and anchoring.

# comment
*.log                # any .log file at any depth
/build/              # only the top-level build/
!important.log       # un-ignore (negation)
docs/**/*.bak        # backup files under docs/

Rules.

  • Trailing /, match directories only.

  • Leading /, anchor to the root.

  • No leading /, match at any depth.

  • !, re-include something previously excluded.

Brace Expansion#

A separate but adjacent feature, not strictly part of glob.

{jpg,png,gif}                # alternation
file_{1,2,3}.txt             # generates three names
[0-9]                        # character class
{01..05}                     # numeric range (Bash)

Brace expansion happens before glob matching in most shells.

Where Glob Appears#

Glob is everywhere there’s a list of filenames to filter – shells, ignore files, sync tools, build systems, editor configs. The list below is a reminder of how broad the footprint is, and why glob is one of the highest-leverage DSLs to keep fluent.

  • Shells, ls *.txt, rm -rf node_modules/*.

  • `.gitignore` / `.dockerignore` / `.gcloudignore`.

  • rsync, --include / --exclude.

  • find, find . -name '*.go'.

  • Build tools, glob / filegroup in Bazel; include / exclude in npm and many others.

  • Editor configurations, .editorconfig, VS Code’s files.exclude.

Pitfalls#

The traps that catch operators new to glob, or operators crossing between shells and tools. Quoting, dotfile handling, ** opt-in semantics, and special-character escaping are the four that come up over and over, each easy to fix once spotted.

  • Quote your patterns in shell when they shouldn’t be expanded by the shell itself: find . -name '*.txt'.

  • ``**`` requires opt-in in many shells.

  • Hidden files, * doesn’t match dotfiles by default.

  • Escape special chars in filenames you want to match literally.

Libraries#

Per-language glob implementations. Coverage of the extended features (**, brace expansion, negation) varies, so the exact library matters when patterns travel across runtimes. The table below points at the standard or most widely used choice in each language.

  • Node, fast-glob, micromatch, minimatch, picomatch.

  • Python, glob (stdlib), pathlib.Path.glob, fnmatch.

  • Go, filepath.Glob (no **), doublestar.

  • Rust, glob crate, globset.

  • Java, FileSystem.getPathMatcher.

Different libraries support different extensions; check the docs before relying on ** or brace expansion.