Globbing and Wildcards
By the end of this lesson you'll be able to match many files at once with the shell's wildcards — * , ? , and bracket sets — generate names with brace expansion, recurse with ** , expand ~ to your home directory, and know exactly when to quote a pattern so the shell leaves it alone.
Learn Globbing and Wildcards in our free Command Line course — an interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Cli course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
1. Set Up a Predictable Sandbox
Globbing matches the files that actually exist, so to get the same output every time we first create a known set of files. Run this once; every later example assumes you're inside this globdemo folder.
2. The * Wildcard: Any Run of Characters
* matches any sequence of characters (including an empty one) within a single filename. Two rules trip people up: a bare * does not match files that begin with a dot (so .hidden is skipped), and * does not cross the / between directories — it stays inside one folder.
3. The ? Wildcard: Exactly One Character
? matches exactly one character — no more, no less. That's the difference between file?.txt (matches file1.txt ) and file??.txt (matches file10.txt ). Use one ? per character you want to leave flexible.
4. Bracket Sets [abc] and Ranges [a-z]
A bracket expression [...] matches exactly one character from the listed set. List choices explicitly with [12] , or give a range with a hyphen like [1-5] or [a-z] . As always, a glob only lists files that truly exist, so a range that matches nothing is passed through literally.
5. Negating a Set with [!...]
Put ! (or ^ ) as the first character inside the brackets to match a single character that is not in the set. So [!1] matches one character that isn't 1 , and [!0-9] matches one non-digit character. Both ! and ^ work in bash.
6. Brace Expansion {a,b} and {1..10} — Not Globbing!
Brace expansion is not globbing. The shell generates strings from the braces before any filename matching, so echo file {1,2,3} .txt prints all three names whether or not the files exist . A real glob like file[1-3].txt only shows files that exist. They combine nicely: the shell expands the braces first, then matches the results as globs.
7. Globstar, Tilde, Quoting, and nullglob
Four power features. ** matches across subdirectories, but only after shopt -s globstar . ~ expands to your home directory (the value of $HOME ). Quoting or escaping a pattern ( "*.txt" or \*.txt ) disables globbing so the literal text is passed along. And by default a glob that matches nothing is left literal — shopt -s nullglob makes it expand to nothing instead.
🎯 Your Turn: match exactly one character
Fill in the blank marked _ using the # 👉 hint so only the single-digit text files match (leaving out file10.txt ), then run it and check the Output panel matches.
🎯 Your Turn: disable globbing with quotes
Make echo print the literal pattern *.txt instead of expanding it, by quoting the argument. Fill in the blank, then run it.
Pro Tips
- 💡 Preview before you act. Run echo PATTERN (or ls PATTERN ) first to see what a glob will match before you put it after rm — globs expand the same way for every command.
- 💡 Globs are the shell's job, regex is the tool's job. ls *.log uses a glob, but grep '^ERROR' *.log uses a glob for the filenames and a regex for the line content. Don't mix up the symbols.
- 💡 Let find do its own matching. In find . -name "*.txt" quote the pattern so the shell doesn't expand it first — find needs to walk every directory itself.
- 💡 Include dotfiles deliberately with shopt -s dotglob , or by writing the leading dot yourself ( .* ). Turn it back off with shopt -u dotglob .
Common Errors (and the fix)
- My program received *.txt literally — there were no matching files, so bash passed the pattern through unchanged. Either create matching files or enable shopt -s nullglob so an empty match expands to nothing.
- * didn't include my .env file — a bare * skips dotfiles by design. Write .* for the hidden ones, or turn on shopt -s dotglob .
- ** only matched the current folder — globstar is off by default. Run shopt -s globstar first to make ** recurse.
- My regex .*\.txt matched nothing as a glob — you mixed up the two languages. In a glob it's *.txt ; the regex form belongs inside tools like grep , not on the command line as a filename.
- rm * deleted more than I expected — the shell expanded * to every non-hidden name before rm ran. Always preview with echo * first, and quote a literal star if you truly mean the character.
📋 Quick Reference
Pattern
Matches
Notes
*
Any run of characters
Skips dotfiles; stays in one dir
?
Exactly one character
One ? per character
[abc]
One char: a, b, or c
Explicit set
[a-z]
One char in a range
Locale-dependent
[!0-9]
One char NOT in the set
^ also negates
{a,b,c}
Generated strings a b c
Not a glob; no files needed
{1..10}
Numeric sequence 1..10
Brace expansion
**
Recurse into subdirs
Needs shopt -s globstar
~
Your home directory
Expands to $HOME
"*.txt"
The literal text *.txt
Quoting disables globbing
Frequently Asked Questions
Mini-Challenge: put the wildcards together
No blanks this time — just a brief and an outline. Combine * , ? , bracket sets, brace expansion, and ** in the globdemo folder, and check your output against the hints in the comments.
🎉 Lesson Complete!
- ✅ * matches any run of characters (but skips dotfiles); ? matches exactly one character
- ✅ Bracket sets [abc] / ranges [a-z] match one character; [!...] or [^...] negates the set
- ✅ Brace expansion {a,b} and {1..10} generates strings — it's NOT globbing and needs no matching files
- ✅ ** recurses after shopt -s globstar ; ~ expands to your home ( $HOME )
- ✅ Globbing matches filenames in the shell while regex matches text in tools; quote a pattern ( "*.txt" ) to disable expansion, and nullglob makes an unmatched glob vanish
- ✅ Next lesson: Command Substitution and Expansion — capture command output with $(...) and combine it with the expansions you just learned
Practice quiz
In bash, what does the * wildcard match by default?
- Any run of characters in a filename, but NOT files that start with a dot
- Exactly one character
- Only files that start with a dot
- Any text including the / between directories
Answer: Any run of characters in a filename, but NOT files that start with a dot. A bare * matches any sequence of characters (including none) in one filename, but dotfiles are skipped unless you write the leading dot yourself or set dotglob.
Which wildcard matches exactly ONE character?
- *
- +
- ?
- .
Answer: ?. ? matches any single character. file?.txt matches file1.txt but not file12.txt.
What does the pattern [a-c]*.txt match?
- Any .txt file
- Files whose name starts with a, b, or c and ends in .txt
- Files named literally a-c.txt
- Only file named abc.txt
Answer: Files whose name starts with a, b, or c and ends in .txt. [a-c] is a character range that matches one character a, b, or c, so the pattern matches names beginning with a, b, or c that end in .txt.
How do you write a bracket expression that matches any single character EXCEPT a digit?
A ! (or ^) as the first character inside the brackets negates the set, so [!0-9] matches one character that is not a digit.
Which statement about brace expansion like {a,b,c} is TRUE?
- It only works if files matching each item exist
- It matches exactly one character like ?
- It is identical to a regex alternation and reads files
- It is NOT globbing; it generates the strings even when no matching file exists
Answer: It is NOT globbing; it generates the strings even when no matching file exists. Brace expansion is pure text generation done before globbing. echo a{1,2,3} prints a1 a2 a3 whether or not those files exist.
What does the numeric brace expansion {1..5} produce?
- 1 2 3 4 5
- Only 1 and 5
- An error in bash
- The single string 1..5
Answer: 1 2 3 4 5. Numeric sequence brace expansion {1..5} expands to 1 2 3 4 5.
What must you do before the ** globstar will match across directory levels in bash?
- Quote the pattern
- Enable it with shopt -s globstar
- Run set -e first
- Nothing, ** always recurses by default
Answer: Enable it with shopt -s globstar. In bash ** behaves like * unless you enable the globstar option with shopt -s globstar, which lets ** match files and directories recursively.
What does the tilde ~ expand to on its own?
- The current directory
- The root directory /
- A single character
- Your home directory, the value of HOME
Answer: Your home directory, the value of HOME. Tilde expansion turns a leading ~ into the path stored in HOME, so ~/notes becomes /home/you/notes.
How can you stop the shell from expanding a glob so a program receives the literal pattern *.txt?
- Use a capital STAR
- It is impossible to disable globbing
- Quote or escape it, for example "*.txt" or \*.txt
- Put a space after the star
Answer: Quote or escape it, for example "*.txt" or \*.txt. Globbing happens on unquoted words. Quoting ("*.txt") or escaping (\*.txt) passes the literal pattern through unchanged.
By default in bash, what happens when a glob like *.md matches no files?
- The command is skipped silently
- The pattern is passed through literally as the text *.md
- The shell prints an error and stops
- It expands to an empty string
Answer: The pattern is passed through literally as the text *.md. By default bash passes the unmatched pattern through literally as text; enabling shopt -s nullglob makes a non-matching glob expand to nothing instead.
Continue this course
- Previous: Environment Variables
- Next: Command Substitution and Expansion