Globs are the wildcard patterns used by shells, build tools, CI pipelines and ignore files to select files. They look alike everywhere, but the details differ between tools, and a pattern that selects slightly too much or too little is easy to miss.
A single * matches within one path segment and never crosses a slash, so *.ts matches index.ts but not src/index.ts. A ** that forms a whole segment matches any number of directories, including none, so **/*.ts matches both. Inside a segment, ** behaves like a single *. At the end of a pattern, a/** needs at least one thing under a, so it matches a/b but not a itself.
*.ts index.ts (not src/index.ts)
**/*.ts index.ts, src/a/b.ts
src/** src/a, src/a/b (not src)By default, * ? [abc] and ** do not match a name that starts with a dot, so * will not select .env and **/*.yml will not enter .github. A pattern segment must itself start with a literal dot to match one, as .* does. Most tools offer a dot option to change this, and it is a frequent reason a config in a hidden folder is silently ignored.
* .env (no match)
.* .env (match)
.github/** .github/workflows/ci.yml (match){js,ts} expands into several patterns before matching, and {1..3} expands to a range of numbers, so *.{js,ts} is the same as *.js plus *.ts. A character class such as [0-9] matches one character from a set, and [!0-9] or [^0-9] matches one outside it. None of them match a slash.
src/**/*.{ts,tsx}
file{1..3}.txt
log[0-9].txtIn a glob, * means any run of characters and . is just a dot. In a regular expression, * repeats the previous item and . means any character, so the same text means something different. Converting is mechanical: * becomes [^/]*, ? becomes [^/], and ** between slashes becomes a repeat of whole directory segments. The tester shows the regular expression each glob is equivalent to.
Open the Glob pattern tester generator
Tools differ on dotfiles, on whether a pattern is tested against the full path or just the file name, on trailing slashes, and on negation with a leading exclamation mark. This tester follows minimatch and Node's path.matchesGlob, which many JavaScript tools use.
Not by default in bash, where it acts like a single *. Enable it with shopt -s globstar. zsh and most build tools support it out of the box.
Escape it with a backslash, as in a\*, or put it in a class, as in a[*]. Both tell the matcher to treat the character as text.