Imagine you need to delete 100 files named file1 through file100, or list all .txt files in a directory, or find all log files that start with "error". Would you type each filename individually? Absolutely not! This is where wildcards become one of your most powerful tools for efficient file management in Linux.
Wildcards (also called glob patterns) allow you to match multiple files using special pattern-matching characters. They work with nearly every file-related command in Linux—ls, rm, cp, mv, find, and many more. Mastering wildcards will save you countless hours and make you significantly more efficient as a system administrator.
🎯 What You'll Learn:
- What wildcards are and how pattern matching works in Linux shells
- The three main wildcard characters:
*,?, and[...] - Character ranges and character classes for precise matching
- Negation patterns to exclude specific characters
- Combining multiple wildcards for complex patterns
- Real-world use cases: bulk operations, filtering, cleanup tasks
- Best practices for safe wildcard usage
- Common pitfalls and how to avoid dangerous mistakes
Series: LFCS Certification - Phase 1 (Post 21 of 52)
Previous Post: Part 20: Understanding Write Permissions and Access Control
Next Post: Part 22: Copying Files with cp Command
What Are Wildcards?
Wildcards (also known as glob patterns or globbing) are special characters that represent one or more characters in filenames. The shell (like bash) expands these patterns into matching filenames before passing them to commands.
How Wildcards Work
When you type a command with wildcards:
ls *.txt
Here's what happens behind the scenes:
- Shell receives the command:
ls *.txt - Shell performs pattern matching: Looks for all files ending in
.txt - Shell expands the pattern: Replaces
*.txtwith matching filenames - Shell executes the command: Runs
ls file1.txt file2.txt notes.txt(actual files)
Wildcard Expansion Process
ls *.txtFinds: file1.txt, file2.txt, notes.txtls file1.txt file2.txt notes.txtLists all three .txt filesKey Concept: Shell Expansion, Not Command Feature
This is crucial to understand: Wildcards are expanded by the shell, not by individual commands. This means wildcards work with ANY command that accepts filenames—ls, rm, cp, mv, cat, grep, and thousands more.
The command itself never sees the wildcard; it only sees the expanded list of matching files.
The Three Main Wildcard Characters
Linux shells support three primary wildcard characters:
| Wildcard | Matches | Example | Matches Files |
|---|---|---|---|
* | Zero or more characters | *.txt | file.txt, notes.txt, a.txt |
? | Exactly one character | file?.txt | file1.txt, filea.txt (NOT file10.txt) |
[...] | Any one character in brackets | file[123].txt | file1.txt, file2.txt, file3.txt only |
Let's explore each in detail with real examples.
The Asterisk (*) - Zero or More Characters
The * (asterisk) is the most commonly used wildcard. It matches zero or more characters of any type.
Basic Examples
# List all files (asterisk matches everything)
ls *
# List all .txt files
ls *.txt
# Matches: file.txt, notes.txt, document.txt, a.txt, etc.
# List all files starting with "file"
ls file*
# Matches: file, file1, file.txt, file_backup, filename, etc.
# List all files containing "log" anywhere in the name
ls *log*
# Matches: logfile.txt, app.log, error_log_2024, mylogdata, etc.
Real Command Output
Let's see * in action:
cd /etc
ls b*
Output:
bashrc bindresvport.blacklist brlapi.key brltty.conf
bash_completion.d:
authselect-completion.sh bpftool iprconfig redefine_filedir tracer vdostats
binfmt.d:
bluetooth:
main.conf
brltty:
Attributes Contraction Input Keyboard Text
What happened?
b*matches all files and directories starting with "b"- Without
-doption,lsshows directory contents (not just the directory name) - Matches:
bashrc(file),bash_completion.d(directory),bluetooth(directory), etc.
Using -d to List Only Directory Names
ls -d b*
Output:
bash_completion.d bashrc bindresvport.blacklist binfmt.d bluetooth brlapi.key brltty brltty.conf
Now we see only the names, not their contents.
Multiple Asterisks in One Pattern
You can use multiple * wildcards in a single pattern:
# Files starting with "file", containing "backup", ending with ".tar.gz"
ls file*backup*.tar.gz
# Matches: file_backup_2024.tar.gz, files_daily_backup.tar.gz
Understanding "Zero or More"
The phrase "zero or more" means * can match nothing:
# Pattern: *.txt
# Matches: .txt (yes, this matches! Zero characters before .txt)
# file.txt (matches)
# longfilename.txt (matches)
The Question Mark (?) - Exactly One Character
The ? (question mark) matches exactly one character—no more, no less.
Basic Examples
# Match file1.txt, file2.txt, filea.txt, but NOT file10.txt
ls file?.txt
# Match log files with single-digit numbers
ls app?.log
# Matches: app1.log, app9.log, appa.log
# Does NOT match: app10.log, app.log
# Match files with exactly 4 characters before .txt
ls ????.txt
# Matches: file.txt, data.txt, test.txt
# Does NOT match: a.txt (3 chars), files.txt (5 chars)
Multiple Question Marks
Each ? represents exactly one character:
# Match files with exactly 2 characters after "file"
ls file??
# Matches: file10, file23, fileab
# Does NOT match: file1, file123
Combining ? with *
# Start with "log", followed by exactly one character, then anything
ls log?*
# Matches: log1.txt, log_error.txt, loga, log1
# Does NOT match: log.txt (no character after "log")
Character Ranges [...] - Specific Character Sets
Square brackets [...] match exactly one character from the set of characters inside the brackets.
Listing Specific Characters
# Match file1.txt, file2.txt, file3.txt ONLY
ls file[123].txt
# Match files starting with a, b, or c
ls [abc]*
# Matches: apple, banana, cherry, a.txt, b123, cat
# Does NOT match: dog, example
Character Ranges with Hyphen
Use a hyphen - to specify a range:
# Match files starting with lowercase letters a through e
ls [a-e]*
Real example from /etc:
cd /etc
ls [a-e]* -d
Output:
accountsservice alternatives asound.conf avahi binfmt.d brltty.conf chrony.keys containers cron.hourly crypto-policies cups debuginfod dkms docker enscript.cfg
adjtime anacrontab at.deny bash_completion.d bluetooth centos-release cifs-utils cron.d cron.monthly crypttab cupshelpers default dnf dracut.conf environment
aliases appstream.conf audit bashrc brlapi.key chromium cockpit cron.daily crontab csh.cshrc dbus-1 depmod.d dnsmasq.conf dracut.conf.d ethertypes
alsa asciidoc authselect bindresvport.blacklist brltty chrony.conf containerd cron.deny cron.weekly csh.login dconf dhcp dnsmasq.d egl exports
This matches all files/directories starting with a, b, c, d, or e.
Common Range Patterns
| Pattern | Matches | Example Matches |
|---|---|---|
[a-z]* | Starts with lowercase letter | apple, zebra, file |
[A-Z]* | Starts with uppercase letter | Apple, ZEBRA, File |
[0-9]* | Starts with a digit | 1file, 2024, 99bottles |
[a-zA-Z]* | Starts with any letter | file, File, ABC |
[a-z0-9]* | Starts with lowercase or digit | file1, 2test, abc |
Combining Multiple Ranges
# Files starting with: a, b, c, or any digit
ls [abc0-9]*
# Files starting with uppercase or lowercase vowels
ls [aeiouAEIOU]*
Negation with [!...] or [^...] - Excluding Characters
Use ! or ^ as the first character inside brackets to negate the pattern—matching any character EXCEPT those listed.
Negation Examples
# Match files NOT starting with a, b, or c
ls [!abc]*
# Matches: dog.txt, zebra, 123, File
# Does NOT match: apple, banana, cat
# Match files NOT starting with a digit
ls [!0-9]*
# Matches: file, test, ABC
# Does NOT match: 1file, 2024, 999
# Match files NOT starting with lowercase letters
ls [!a-z]*
# Matches: ABC, File, 123, _test
# Does NOT match: file, test, abc
Practical Use Case: Finding Non-Hidden Files
In Linux, hidden files start with a dot .. To list only non-hidden files:
# List all files NOT starting with a dot
ls [!.]*
This is useful when you want to exclude .bashrc, .profile, and other dotfiles.
Combining Wildcards - Advanced Patterns
The real power comes from combining multiple wildcards in sophisticated patterns.
Complex Pattern Examples
# Files starting with "file", then 1-3 digits, ending with .txt
ls file[0-9][0-9][0-9].txt
# Matches: file001.txt, file123.txt, file999.txt
# Does NOT match: file1.txt, file12.txt, file1234.txt
# Log files with year 2023 or 2024
ls app-202[34]*.log
# Matches: app-2023-01-15.log, app-2024-12-31.log
# Does NOT match: app-2022.log, app-2025.log
# Backup files ending with .bak or .backup
ls *{.bak,.backup}
# Note: This uses brace expansion (not strictly a wildcard, but commonly combined)
Real-World Pattern
Suppose you have these files:
error_2024-01-15.log
error_2024-02-20.log
warning_2024-01-15.log
info_2024-01-15.log
To match only error logs from January 2024:
ls error_2024-01-*.log
To match all logs from 2024 (any month, any day):
ls *_2024-*.log
To match error and warning logs only:
ls error_*.log warning_*.log
# Or use character matching:
ls [ew]*_*.log # Files starting with 'e' or 'w'
Wildcards with Common Commands
Wildcards work with virtually every file-related command. Let's see practical examples.
Listing Files (ls)
# All .conf configuration files
ls *.conf
# All files with exactly 4 characters
ls ????
# All files starting with letters a-m
ls [a-m]*
Removing Files (rm)
⚠️ EXTREME CAUTION: Always double-check wildcard patterns with ls before using with rm!
SAFE workflow:
- First:
ls file*(verify matches) - Then:
rm file*(delete matches)
NEVER run rm with wildcards without testing first!
# Remove all .tmp files
ls *.tmp # First, verify what will be deleted
rm *.tmp # Then, delete
# Remove files file11 through file20
ls file1[0-9] # Verify first
rm file1[0-9] # Then delete
Copying Files (cp)
# Copy all .txt files to backup directory
cp *.txt /backup/
# Copy all files starting with "report" to archive
cp report* /archive/
# Copy all .jpg and .png images
cp *.jpg *.png /images/
Moving Files (mv)
# Move all log files to logs directory
mv *.log logs/
# Move files file50 through file99
mv file[5-9][0-9] /tmp/
Viewing Files (cat, less, grep)
# Display all .txt files
cat *.txt
# Search for "error" in all log files
grep "error" *.log
# Page through all markdown files
less *.md
Special Case: Hidden Files and Dotfiles
In Linux, files starting with . (dot) are hidden files. Wildcards have special behavior with these files.
Default Behavior: Wildcards Don't Match Dotfiles
# This does NOT match .bashrc, .profile, etc.
ls *
The * wildcard does not match files starting with . by default. This is a safety feature to prevent accidental deletion of configuration files.
Explicitly Matching Dotfiles
# Match hidden files explicitly
ls .*
# Match all files starting with .bash
ls .bash*
# Matches: .bashrc, .bash_profile, .bash_history
Matching Both Hidden and Regular Files
# List everything (including hidden files)
ls .* *
# Or use ls -a (which includes . and ..)
ls -a
💡 Why This Matters: This behavior prevents accidentally deleting important configuration files with commands like rm * (which won't delete .bashrc, .profile, etc.).
Brace Expansion: Creating Multiple Files Efficiently
While not strictly a wildcard, brace expansion is often used alongside wildcards for efficient file operations.
Brace Expansion Syntax
# Create files file1, file2, ..., file100
touch file{1..100}
What happens:
- Shell expands
{1..100}to:1 2 3 4 ... 100 - Becomes:
touch file1 file2 file3 ... file100
Real example from our source material:
touch file{1..100}
ls
Output:
file1 file10 file100 file11 file12 ... file99
Removing with Wildcards After Brace Creation
# Remove file1 through file10
rm file{1..10}
# Or use wildcards
rm file[1-9] # Removes file1-file9
rm file1[0-9] # Removes file10-file19
Combining Brace Expansion with Wildcards
# Create backup files
cp file.txt{,.backup}
# Expands to: cp file.txt file.txt.backup
# Create multiple directories
mkdir -p project/{src,bin,docs,tests}
Understanding When Wildcards Don't Match
If a wildcard pattern matches no files, different shells behave differently:
Bash Behavior (Default)
# If no .xyz files exist
ls *.xyz
Output:
ls: cannot access '*.xyz': No such file or directory
Bash passes the literal string *.xyz to ls when no matches are found.
Setting nullglob Option
You can change this behavior:
# Enable nullglob: unmatched patterns expand to nothing
shopt -s nullglob
ls *.xyz
# If no matches, expands to: ls
# (lists current directory instead of error)
💡 For LFCS Exam: You don't need to set nullglob. Just understand that if wildcards don't match anything, you'll get "No such file or directory" errors.
Escaping Wildcards: Using Literal *, ?, [
What if you have a file actually named file*.txt (with a literal asterisk)? You need to escape the wildcard.
Escaping with Backslash
# Create a file with asterisk in name
touch "file*.txt"
# List it using escaped wildcard
ls file\*.txt
# Matches: file*.txt (the literal filename)
# Without escaping
ls file*.txt
# Matches: file1.txt, file2.txt, fileA.txt, etc.
Escaping with Quotes
# Single or double quotes prevent expansion
ls 'file*.txt'
ls "file*.txt"
# Both match: file*.txt (literal)
⚠️ Best Practice: Avoid using wildcard characters in filenames. It causes confusion and complicates automation scripts.
Real-World Use Cases
Let's explore practical scenarios where wildcards save massive amounts of time.
Use Case 1: Log File Cleanup
Delete old log files from a specific month:
# Delete all January 2023 logs
cd /var/log/myapp
ls app-2023-01-*.log # Verify first
rm app-2023-01-*.log # Then delete
Use Case 2: Backup All Configuration Files
# Copy all .conf files to backup directory
cp /etc/*.conf /backup/etc-configs/
# Copy all files starting with "my" from home directory
cp ~/my* /backup/my-files/
Use Case 3: Finding Recently Modified Files
# List all .txt files modified today
ls -lt *.txt | head
# Count number of .log files
ls *.log | wc -l
Use Case 4: Organizing Files by Extension
# Move all images to images directory
mv *.jpg *.png *.gif images/
# Move all documents to documents directory
mv *.pdf *.doc *.docx documents/
Use Case 5: Batch Renaming with Wildcards
# Rename all .txt files to .bak
for file in *.txt; do
mv "$file" "${file%.txt}.bak"
done
(We'll cover for loops in later posts, but this shows the power of combining wildcards with scripting.)
Use Case 6: Selective Archive Extraction
# Extract only .html files from tar archive
tar xf archive.tar --wildcards "*.html"
Common Wildcard Patterns Quick Reference
| Task | Pattern | Example |
|---|---|---|
| All files with specific extension | *.ext | ls *.pdf |
| Files starting with prefix | prefix* | ls error_* |
| Files ending with suffix before extension | *suffix.ext | ls *_backup.tar.gz |
| Files with single digit | file?.ext | ls file[0-9].txt |
| Files with two digits | file[0-9][0-9] | ls file[0-9][0-9].log |
| Files starting with specific letters | [abc]* | ls [abc]* |
| Files starting with letter range | [a-m]* | ls [a-m]*.txt |
| Files NOT starting with letters | [!a-z]* | ls [!a-z]* |
| Hidden files (dotfiles) | .* | ls .* |
| All files except hidden | [!.]* | ls [!.]* |
| Logs from specific year-month | *YYYY-MM*.log | ls *2024-01*.log |
| Multiple extensions | *.ext1 *.ext2 | ls *.jpg *.png |
🧪 Practice Labs
Now it's time for hands-on practice! These 20 labs progress from basic to advanced wildcard usage.
💡 Lab Setup: Create a practice directory for these exercises:
mkdir ~/wildcard-practice
cd ~/wildcard-practice
Lab 1: Creating Test Files (Beginner)
Task: Create 50 files named file1 through file50 using brace expansion.
Show Solution
# Create files using brace expansion
touch file{1..50}
# Verify creation
ls file*
# or
ls | wc -l # Should show 50
Explanation:
{1..50}expands to numbers 1 through 50touchcreates empty filesfile*wildcard matches all files starting with "file"
Lab 2: Listing Files with Asterisk (Beginner)
Task: List only files that start with "file" and end with a single digit (file1-file9).
Show Solution
# List files with single digit
ls file[1-9]
# Alternative using ?
ls file?
# Note: This matches file1-file9, but ALSO matches filea, fileb, etc. if they exist
# Best solution for single digits only
ls file[0-9]
# This matches file0-file9 (single digits only)
Explanation:
[1-9]matches exactly one character: 1, 2, 3, 4, 5, 6, 7, 8, or 9file[1-9]matches file1, file2, ... file9- Does NOT match file10, file11, etc. (those have two digits)
Lab 3: Listing Two-Digit Files (Beginner)
Task: List only files numbered 10-50 (two digits).
Show Solution
# List files with two digits
ls file[0-9][0-9]
# Alternative: list files 10-50 specifically
ls file[1-5][0-9]
# This matches file10-file59 (too broad)
# Better: match 10-19, 20-29, 30-39, 40-49, 50
ls file1[0-9] file2[0-9] file3[0-9] file4[0-9] file50
Explanation:
[0-9][0-9]matches exactly two digitsfile[0-9][0-9]matches file10, file23, file50, etc.- Each
[0-9]represents one digit position
Lab 4: Creating Files with Extensions (Beginner)
Task: Create the following files:
document1.txt,document2.txt,document3.txtimage1.jpg,image2.jpg,image3.jpgscript1.sh,script2.sh,script3.sh
Show Solution
# Create document files
touch document{1..3}.txt
# Create image files
touch image{1..3}.jpg
# Create script files
touch script{1..3}.sh
# Verify all created
ls
Explanation:
{1..3}expands to 1, 2, 3.txt,.jpg,.share appended after the number- Results: document1.txt, document2.txt, document3.txt, etc.
Lab 5: Listing Files by Extension (Beginner)
Task: List only .txt files, then only .jpg files, then only .sh files.
Show Solution
# List .txt files
ls *.txt
# List .jpg files
ls *.jpg
# List .sh files
ls *.sh
# List all three types in one command
ls *.txt *.jpg *.sh
Explanation:
*.txtmatches all files ending in.txt*matches zero or more characters before.txt- Multiple patterns can be used in one command
Lab 6: Question Mark Wildcard (Intermediate)
Task: Create files log1.txt through log9.txt, then create log10.txt and log100.txt. Use wildcards to list ONLY the single-digit log files.
Show Solution
# Create files
touch log{1..9}.txt log10.txt log100.txt
# List ALL log files (to see what we have)
ls log*.txt
# List ONLY single-digit log files (log1.txt through log9.txt)
ls log?.txt
# Verify: this should show log1.txt through log9.txt
# Does NOT show log10.txt or log100.txt (they have more than one character between "log" and ".txt")
Explanation:
?matches exactly ONE characterlog?.txtmatches log1.txt (one digit), log2.txt, etc.- Does NOT match log10.txt (two characters: "10")
Lab 7: Character Ranges (Intermediate)
Task: Create files a.txt, b.txt, c.txt, ... z.txt. Then list only files from a.txt through m.txt.
Show Solution
# Create files a.txt through z.txt
touch {a..z}.txt
# List only a.txt through m.txt
ls [a-m].txt
# Alternative: verify by listing all, then filtered
ls *.txt # All files
ls [a-m].txt # First half of alphabet
ls [n-z].txt # Second half of alphabet
Explanation:
{a..z}creates files from a to z[a-m]matches any single character in range a through m[a-m].txtmatches a.txt, b.txt, ... m.txt
Lab 8: Negation Patterns (Intermediate)
Task: Using the files from Lab 7, list all .txt files that do NOT start with vowels (a, e, i, o, u).
Show Solution
# List all .txt files NOT starting with vowels
ls [!aeiou]*.txt
# Alternative using ^
ls [^aeiou]*.txt
# Both produce the same result: files starting with consonants
Explanation:
[!aeiou]matches any character EXCEPT a, e, i, o, u*matches any remaining characters.txtmatches the extension- Result: b.txt, c.txt, d.txt, f.txt, g.txt, ... (all consonants)
Lab 9: Combining Multiple Wildcards (Intermediate)
Task: Create files with this pattern: report_2024-01-15.txt, report_2024-02-20.txt, report_2024-03-10.txt, report_2023-12-05.txt. List only 2024 reports.
Show Solution
# Create the files
touch report_2024-01-15.txt report_2024-02-20.txt report_2024-03-10.txt report_2023-12-05.txt
# List only 2024 reports
ls report_2024*.txt
# Alternative: more specific pattern
ls report_2024-*.txt
# Even more specific: 2024 January reports only
ls report_2024-01*.txt
Explanation:
report_2024*.txtmatches files starting with "report_2024"*matches everything between "2024" and ".txt"- Matches: report_2024-01-15.txt, report_2024-02-20.txt, etc.
- Does NOT match: report_2023-12-05.txt
Lab 10: Safe File Deletion (Intermediate)
Task: Delete only files file11 through file20. Use ls to verify first, then delete.
Show Solution
# STEP 1: Verify what will be deleted
ls file1[0-9]
# Should show: file10, file11, file12, ... file19
# Hmm, we want file11-file20, not file10-file19
# Better pattern:
ls file1[1-9] file20
# Shows: file11, file12, ... file19, file20
# STEP 2: Delete after verification
rm file1[1-9] file20
# STEP 3: Verify deletion
ls file*
# Should NOT show file11-file20 anymore
Explanation:
- ALWAYS use
lsto verify beforerm file1[1-9]matches file11 through file19file20is listed separately- Combining patterns:
file1[1-9] file20
Lab 11: Working with Hidden Files (Intermediate)
Task: Create hidden files .config1, .config2, .config3. List them using wildcards.
Show Solution
# Create hidden files
touch .config{1..3}
# Try listing with * (won't work)
ls *
# Does NOT show .config files
# Explicitly list hidden files
ls .*
# List specific hidden files
ls .config*
# Verify
ls -a | grep config
Explanation:
- Files starting with
.are hidden *does NOT match hidden files (safety feature).*explicitly matches hidden files.config*matches all files starting with ".config"
Lab 12: Multiple File Extensions (Intermediate)
Task: List all .txt, .jpg, and .sh files in one command.
Show Solution
# List multiple extensions in one command
ls *.txt *.jpg *.sh
# Count how many files total
ls *.txt *.jpg *.sh | wc -l
# Alternative with extended globbing (optional)
# Enable extglob first
shopt -s extglob
ls *.@(txt|jpg|sh)
Explanation:
- Multiple wildcard patterns separated by spaces
- Shell expands each pattern independently
- All matching files are passed to
ls
Lab 13: Copying with Wildcards (Intermediate)
Task: Create a backup directory. Copy all .txt files to it.
Show Solution
# Create backup directory
mkdir backup
# Verify .txt files exist
ls *.txt
# Copy all .txt files to backup
cp *.txt backup/
# Verify copy
ls backup/
Explanation:
mkdircreates directory*.txtmatches all .txt filescp *.txt backup/copies all matches to backup/- Trailing
/indicates directory destination
Lab 14: Exact Character Count (Advanced)
Task: Create files with names of exactly 5 characters before .txt (e.g., alpha.txt, bravo.txt). List only files with exactly 5-character names.
Show Solution
# Create files with 5-character names
touch alpha.txt bravo.txt charm.txt delta.txt a.txt ab.txt abcdef.txt
# List only files with exactly 5 characters before .txt
ls ?????.txt
# Verify
ls *.txt # All .txt files
ls ?????.txt # Only 5-character names
Explanation:
- Each
?represents exactly one character ?????matches exactly 5 characters?????.txtmatches alpha.txt, bravo.txt, etc.- Does NOT match: a.txt (1 char), ab.txt (2 chars), abcdef.txt (6 chars)
Lab 15: Complex Date Patterns (Advanced)
Task: Create log files for January and February 2024:
app-2024-01-01.logthroughapp-2024-01-31.logapp-2024-02-01.logthroughapp-2024-02-29.log
List only February 2024 logs.
Show Solution
# Create January logs (simplified: just 1-5 for demo)
touch app-2024-01-{01..05}.log
# Create February logs (simplified: just 1-5 for demo)
touch app-2024-02-{01..05}.log
# List only February logs
ls app-2024-02*.log
# More specific: February logs only
ls app-2024-02-[0-9][0-9].log
# Even more specific: February 1-9 vs 10-29
ls app-2024-02-0[1-9].log # Feb 01-09
ls app-2024-02-[12][0-9].log # Feb 10-29
Explanation:
app-2024-02*.logmatches all February logs[0-9][0-9]ensures two-digit day format- Date patterns can be very specific with ranges
Lab 16: Excluding Specific Patterns (Advanced)
Task: List all files EXCEPT those ending in .log or .tmp.
Show Solution
# Create various file types
touch file.txt file.log file.tmp file.sh file.py
# This is tricky with wildcards alone
# Method 1: Use ls with grep to filter OUT
ls | grep -v -E '\.(log|tmp)$'
# Method 2: Use extended globbing (bash)
shopt -s extglob
ls !(*.log|*.tmp)
# Method 3: List specific extensions you WANT
ls *.txt *.sh *.py
Explanation:
- Wildcards match patterns, but excluding is harder
grep -vinverts the match (shows non-matches)- Extended globbing
!(pattern)excludes patterns - Often easier to specify what you WANT rather than exclude
Lab 17: Case-Sensitive Matching (Advanced)
Task: Create files File.txt, FILE.txt, file.txt. List only lowercase file.txt.
Show Solution
# Create files
touch File.txt FILE.txt file.txt
# List all
ls *.txt
# List only lowercase file.txt (exact match needed)
ls file.txt
# To match any case, you'd need multiple patterns
ls [Ff][Ii][Ll][Ee].txt
# Matches: File.txt, FILE.txt, file.txt, etc.
Explanation:
- Linux filenames are case-sensitive
file.txtis different fromFile.txt- Wildcards are also case-sensitive
[Ff]matches F or f (one character)
Lab 18: Nested Directory Wildcards (Advanced)
Task: Create subdirectories dir1, dir2, dir3 with files inside each. List all .txt files in all subdirectories.
Show Solution
# Create directories and files
mkdir dir{1..3}
touch dir1/{a,b,c}.txt
touch dir2/{x,y,z}.txt
touch dir3/{1,2,3}.txt
# List .txt files in all subdirectories
ls dir*/*.txt
# Alternative: more specific
ls dir[1-3]/*.txt
# Show directory structure
ls -R dir*
Explanation:
dir*matches all directories starting with "dir"/separates directory and filename*.txtmatches .txt files inside each directorydir*/*.txtexpands to: dir1/.txt dir2/.txt dir3/*.txt
Lab 19: Wildcard Safety Test (Advanced)
Task: Create a file named * (yes, literally an asterisk). Practice safely listing and deleting it without affecting other files.
Show Solution
# Create a file named * (literal asterisk)
touch "*"
# Verify it exists
ls -l
# Dangerous: DO NOT just type "rm *"
# That would delete ALL files!
# Safe method 1: Escape the asterisk
ls \*
rm \*
# Safe method 2: Use quotes
ls '*'
rm '*'
# Safe method 3: Use ./ prefix
ls ./*
rm ./"*"
# Verify deletion
ls -l
Explanation:
- Files can have wildcard characters in their names (not recommended!)
- Escaping with
\makes the character literal - Quotes prevent shell expansion
./*makes the shell treat it as a path, not a pattern
Lab 20: Real-World Cleanup Script (Advanced)
Task: Write a complete workflow to:
- Create 100 test files
- List files 50-100
- Verify count
- Delete files 50-100
- Verify deletion
Show Solution
# Step 1: Create 100 test files
touch testfile{1..100}.txt
echo "Created 100 files"
# Step 2: List files 50-100 (verify what we'll delete)
echo "Files to be deleted:"
ls testfile[5-9][0-9].txt testfile100.txt
# Step 3: Count how many files will be deleted
echo "Count of files to delete:"
ls testfile[5-9][0-9].txt testfile100.txt | wc -l
# Should be 51 files (50-99 = 50 files, plus 100 = 51 total)
# Step 4: Delete files 50-100
echo "Deleting files 50-100..."
rm testfile[5-9][0-9].txt testfile100.txt
# Step 5: Verify deletion
echo "Remaining files count:"
ls testfile*.txt | wc -l
# Should be 49 files (1-49 remaining)
echo "Remaining files:"
ls testfile*.txt
Explanation:
- Always verify before deleting with
ls - Use
wc -lto count files [5-9][0-9]matches 50-99- Add
testfile100.txtseparately - Verify after deletion to confirm success
📚 Best Practices
✅ DO
- Test with ls first: Always verify wildcard matches with
lsbefore using destructive commands likerm - Use quotes when needed: Quote patterns containing spaces or special characters
- Be specific: Use
*.txtinstead of*when possible - Use character ranges:
[0-9]is clearer than?for digits - Understand expansion: Remember the shell expands wildcards, not the command
- Use -i with rm:
rm -i *.txtprompts before each deletion - Check current directory: Always know where you are with
pwdbefore using wildcards - Practice in safe directory: Test patterns in a practice directory first
❌ DON'T
- Never use rm * in important directories without verification
- Don't use wildcards in filenames: Avoid naming files
file*.txt - Don't assume no matches: Check if pattern matched anything
- Don't forget hidden files:
*doesn't match dotfiles - Don't mix up * and ?: They behave very differently
- Don't use wildcards with sudo carelessly:
sudo rm *in wrong directory = disaster - Don't rely on memory: Always verify current directory and matches
- Don't skip the safety check: One mistake with
rmcan't be undone
The Golden Rule: Test → Verify → Execute
# 1. TEST: See what the pattern matches
ls *.log
# 2. VERIFY: Count how many files
ls *.log | wc -l
# 3. EXECUTE: Perform the operation
rm *.log
🚨 Common Pitfalls to Avoid
Pitfall 1: Deleting Wrong Files
# DANGEROUS: Accidentally in wrong directory
cd /important/data
rm * # Deletes EVERYTHING in current directory!
# SAFE: Always verify location first
pwd
ls
ls * # Verify what would be deleted
rm * # Only after verification
Pitfall 2: Forgetting Hidden Files
# This does NOT back up .bashrc, .profile, etc.
cp * backup/
# To include hidden files
cp * .* backup/
# Or
cp -r . backup/
Pitfall 3: Wildcards in Variable Expansion
# Dangerous pattern
FILES="*"
rm $FILES # Expands to all files!
# Safe pattern
FILES="*.txt"
rm "$FILES" # Quotes prevent expansion issues
Pitfall 4: No Matches = Error
# If no .xyz files exist
rm *.xyz
# Error: rm: cannot access '*.xyz': No such file or directory
# The literal string *.xyz is passed to rm
Pitfall 5: Case Sensitivity Confusion
# These are different files on Linux
file.txt
File.txt
FILE.TXT
# This matches only lowercase
ls *.txt
# Does NOT match .TXT or .Txt
Pitfall 6: Spaces in Filenames
# If files have spaces: "my file.txt"
ls my file.txt # Tries to list "my" and "file.txt"
# Correct:
ls "my file.txt"
ls my\ file.txt
ls *file.txt # Wildcard handles spaces
Pitfall 7: Overlapping Patterns
# Both patterns match some same files
cp file*.txt backup/
cp *report*.txt backup/
# If "file_report.txt" exists, it's copied twice
# Use combined pattern instead:
cp file*.txt *report*.txt backup/
📝 Command Cheat Sheet
# ===== BASIC WILDCARDS =====
ls * # All files (not hidden)
ls *.txt # All .txt files
ls file* # Files starting with "file"
ls *backup* # Files containing "backup"
# ===== QUESTION MARK =====
ls file?.txt # file1.txt, filea.txt (one character)
ls file?? # file10, fileab (two characters)
ls ?????.txt # Files with exactly 5 chars before .txt
# ===== CHARACTER RANGES =====
ls [abc]* # Files starting with a, b, or c
ls [0-9]* # Files starting with digit
ls [a-z]* # Files starting with lowercase letter
ls [A-Z]* # Files starting with uppercase letter
ls [a-zA-Z]* # Files starting with any letter
ls file[1-5].txt # file1.txt through file5.txt
# ===== NEGATION =====
ls [!abc]* # Files NOT starting with a, b, or c
ls [!0-9]* # Files NOT starting with digit
ls [!.]* # Non-hidden files (not starting with .)
# ===== COMBINING WILDCARDS =====
ls file[0-9]*.txt # file1.txt, file123.txt
ls *[0-9][0-9].log # Files ending with two digits + .log
ls [a-z]*[0-9].txt # Start with letter, end with digit + .txt
# ===== HIDDEN FILES =====
ls .* # All hidden files
ls .bash* # Hidden files starting with .bash
ls .config* # Hidden files starting with .config
# ===== COMMON OPERATIONS =====
rm *.tmp # Delete all .tmp files
cp *.txt backup/ # Copy all .txt files to backup/
mv *.log logs/ # Move all .log files to logs/
cat *.txt # Display all .txt files
# ===== BRACE EXPANSION =====
touch file{1..100} # Create file1 to file100
mkdir dir{1..5} # Create dir1 to dir5
cp file.txt{,.backup} # Copy file.txt to file.txt.backup
rm file{1..10} # Delete file1 to file10
# ===== ESCAPING WILDCARDS =====
ls \* # List file literally named *
ls '*.txt' # List file literally named *.txt
rm "*" # Remove file literally named *
# ===== VERIFICATION WORKFLOW =====
ls *.log # 1. See what matches
ls *.log | wc -l # 2. Count matches
rm *.log # 3. Delete after verification
# ===== NESTED DIRECTORIES =====
ls */*.txt # .txt files in all subdirectories
ls dir*/*.log # .log files in dirs starting with "dir"
🎯 Key Takeaways
✅ Master These Concepts:
- Wildcards are shell features, not command features—they work with ANY command
*matches zero or more characters—the most flexible wildcard?matches exactly one character—useful for precise patterns[...]matches one character from a set—powerful for specific ranges[!...]negates the match—excludes specific characters- Always test with
lsbeforerm—safety first! - Hidden files (.dotfiles) need explicit
.*pattern—*won't match them - Wildcards don't match across directory separators—use
*/*for nested dirs - Quote or escape literal wildcard characters—when files actually contain *, ?, [
- Combine wildcards for sophisticated patterns—
file[0-9][0-9].txt,*backup*.tar.gz
LFCS Exam Tips:
- Wildcards appear in almost every file management task
- Know how to safely delete specific file ranges
- Understand character ranges for filtering files
- Remember hidden files behavior
- Practice complex patterns until they're second nature
🚀 What's Next?
You've now mastered wildcards—one of the most powerful tools for efficient file management in Linux! You can now match files using patterns, perform bulk operations safely, and understand how the shell expands these patterns.
In the next post, we'll learn about copying files with the cp command, including:
- Basic file and directory copying
- Recursive copying with
-r - Preserving file attributes with
-p - Interactive mode with
-i - Copying multiple files and entire directory trees
- Using wildcards with
cpfor bulk operations
Wildcards will make copying operations dramatically more efficient!
🎉 Congratulations! You've mastered Linux wildcards and pattern matching! You can now perform bulk file operations with confidence, match files precisely using character ranges, and understand how the shell expands patterns. These skills will save you countless hours throughout your Linux career.
Practice makes perfect: Spend time experimenting with wildcards in a safe practice directory. The more you use them, the more natural they'll become!
Remember: Always verify with ls before using destructive commands like rm. One moment of verification can save hours of recovery work.

