A practical, system-level guide to understanding wildcards (globbing) in the Linux command line — how globbing really works, how shells differ, and the pitfalls worth knowing.
What wildcards really are
Wildcards are pattern-matching characters expanded by the shell itself, not by commands like ls, cp, or rm.
ls *.txtWhat actually happens:
shell expands *.txt → file1.txt file2.txt
ls file1.txt file2.txtCommands never see wildcards — they only receive expanded filenames.
Globbing vs. regular expressions
| Feature | Wildcards (Globs) | Regex |
|---|---|---|
| Expanded by | Shell | Program |
| Syntax | Simple | Complex |
| Recursive | Limited | Yes |
| Context | Filenames | Text content |
Example confusion:
ls .*txt # glob
ls | grep .*txt # regexExpansion order (important)
Shell expansion happens in a defined order: brace expansion {} → tilde expansion ~ → parameter expansion $VAR → command substitution $( ) → pathname expansion (globbing) → quote removal. This affects correctness and safety.
Types of wildcards
Asterisk *
Matches zero or more characters, and does not cross directory separators (/).
*.log
backup*Question mark ?
Matches exactly one character.
file?.txt # file1.txt matches | file10.txt does notCharacter classes [ ]
file[1-3].txt
file[a-z].txt
file[!0-9].txt # NOT digitsBrace expansion {} (not a wildcard!)
Brace expansion generates strings before globbing.
echo file{1,2,3}.txtfile1.txt file2.txt file3.txtRanges:
echo {a..d}
echo {01..10}Advanced globbing patterns
Enable extended globbing:
shopt -s extglob*.!(txt) # anything except txt
*@(jpg|png)Requires Bash or Zsh.
Hidden files and dotfiles
* does NOT match .hidden. .* matches dotfiles, but also . and ...
Safe pattern:
ls .[^.]*Recursive globbing **
shopt -s globstar
ls **/*.cConceptually equivalent to:
find . -name "*.c"Wildcards with common commands
cp *.txt /backup/
rm report[0-9].txt
mv *.log old_logs/
chmod +x *.shAlways test first:
echo rm *.logWildcards vs. find
| Use Case | Wildcards | find |
|---|---|---|
| Recursive | No | Yes |
| Size / time filters | No | Yes |
| Performance (small dirs) | Yes | No |
Use globs for simple cases, find for complex logic.
Quoting & escaping
Disable expansion completely:
echo "*.txt"Escape a single wildcard:
echo \*.txtWhy it matters:
rm "$file"Safety techniques (very important)
Dry-run everything:
echo rm *.logFail on no matches:
shopt -s failglobPrevent dangerous deletes:
rm -- -file.txtPerformance considerations
Globbing happens before execution; large directories mean memory expansion cost. Use find for thousands of files.
getconf ARG_MAXShell differences
| Feature | sh | bash | zsh |
|---|---|---|---|
| Brace expansion | No | Yes | Yes |
Recursive ** |
No | Yes | Yes |
| Extended glob | No | Yes | Yes |
| Safer defaults | No | No | Yes |
Real-world use cases
# Cleanup logs
rm /var/log/*.{1,old}
# Project setup
mkdir -p app/{src,bin,docs,tests}
# Batch rename preview
echo mv *.jpeg *.jpgCommon mistakes
Believing commands interpret wildcards, forgetting hidden files, mixing regex with glob syntax, and unquoted variables.
Exercises
Beginner:
ls *.txtIntermediate:
find . -name "*.log" -mtime -3Advanced:
shopt -s globstar extglob
ls **/*.!(*.tmp)Understanding globbing gives you precision, safety, and speed at the command line.
Comments
Loading the discussion…