Glob patterns and brace expansion
Shell substitutions — * ? [] {} — and how they differ from regular expressions.
Cheat sheet
9 commands
Printable version
-
*.log ? [0-9] [!a]
glob: string / char / range / negated
-
mkdir -p p/{src,tests,docs}
brace expansion
-
cp file{,.bak}
a quick backup
-
echo {1..5}
a sequence
-
echo {01..10..2}
a sequence with a step
-
shopt -s globstar
enable recursive **
-
ls **/*.log
a recursive pattern search
-
shopt -s extglob
enable extended patterns
-
rm !(*.keep)
remove everything except *.keep
- glob works on filenames, regex works on content (grep/sed)
Overview
The shell expands filename patterns (globbing) itself, before running
the command. This is not regex — the syntax is different and simpler.
ls *.log
rm tmp_?
ls report-[0-9].txt
Options
shopt -s globstar
shopt -s nullglob
shopt -s dotglob
shopt -s nocaseglob
shopt -s extglob
shopt -s failglob
extglob examples: rm !(*.keep) (everything except .keep), ls @(*.jpg|*.png).
Recipes
2
| Pattern |
Meaning |
* |
any string (including empty), except / |
? |
exactly one character |
[abc] [!abc] |
one of / anything but |
[0-9] [a-z] |
a range |
** |
recursively through subdirectories (with shopt -s globstar) |
Brace expansion {} is not a glob (it always expands, even with no matching files):
mkdir -p project/{src,tests,docs}
cp file.conf{,.bak}
mv app.{js,ts}
echo {1..5} ; echo {01..10..2}
echo img-{a,b,c}.png
- glob is for filenames in the shell;
* means "anything".
- regex is for content in grep/sed; there
* means
"0 or more of the previous thing", and "anything" is .*.
Don't confuse them: ls *.txt (glob) is not grep '*.txt' (regex — you need
grep '\.txt').
Troubleshooting
4
SymptomCause and fix
The pattern found no files — the command got the literal pattern
By default bash leaves an unmatched glob as-is (ls *.xyz → "no such file:
*.xyz"). Turn on shopt -s nullglob (it vanishes) or failglob (an error).
Hidden files didn't get caught by *
* doesn't include files starting with .. Use .* separately, or shopt -s
dotglob (careful: .* also matches . and ..).
Spaces/special characters in names break things
Quote your variables; for bulk processing, use find -print0 | xargs -0
(see xargs).
{a,b} didn't expand
There must be no spaces inside: {a, b} won't work. And it's not a glob — it
expands before files are even checked.
See also
- files-basics — Navigation and files — ls, cd, cp, mv, rm, cat, less, head, tail, terminal copy-paste.
- find — Finding files by name, size, time, permissions; acting on what's found.
- regex — Patterns for grep/sed/awk — characters, classes, anchors, groups; basic vs. extended.
Found an inaccuracy? Report an error in the article