Complete Guide to Linux Wildcards: How to Use *, ?, and [] Glob Patterns
In the Linux command line, Wildcards (glob patterns) are powerful tools for batch file operations. By mastering the
*,?, and[]wildcards along with Brace Expansion, you can accomplish batch operations in a single command that would otherwise require dozens of lines, dramatically improving your productivity.
What Is a Wildcard?
A Wildcard (also known as a glob pattern) is a special character that the Shell uses when parsing commands to match multiple filenames. When you type ls *.txt, the Shell first expands *.txt into all matching filenames in the current directory, then passes the complete file list to the ls command.
This expansion process is called Globbing, and it is a Shell feature — not a feature of commands like ls, cp, or rm themselves. This is important to understand: Wildcard expansion occurs before the command is executed.
Main uses of Wildcards:
- Batch copy, move, or delete files that match a specific naming pattern
- List only files with a specific extension
- Quickly select a series of numbered files
- Combine with
find,grep, and other commands for advanced searching
Complete Wildcard Syntax Table
| Wildcard | Name | Description | Example | Matches |
|---|---|---|---|---|
* | Asterisk | Matches any number of any characters (including zero characters) | *.txt | a.txt, readme.txt, hello.txt |
? | Question mark | Matches exactly one character | file?.txt | file1.txt, fileA.txt (does not match file10.txt) |
[abc] | Character set | Matches any single character within the brackets | file[123].txt | file1.txt, file2.txt, file3.txt |
[a-z] | Character range | Matches any single character within the specified range | file[a-z].txt | filea.txt, fileb.txt, …filez.txt |
[!abc] | Negated character set | Matches any single character not in the brackets | file[!0-9].txt | filea.txt, fileb.txt (does not match file1.txt) |
Basic Wildcard Usage
* Asterisk – Match Any Characters
# List all text files in the current directory
ls *.txt
# List all .jpg and .png images
ls *.jpg
ls *.png
# List all files starting with "report" (any extension)
ls report*
# Copy all JPEG images to a specified directory
cp *.jpg /home/benz/backup/images/
# Move all PNG images to a backup directory
mv *.png /home/benz/backup/
# Delete all temporary .tmp files (use ls first to verify which files will be deleted)
ls *.tmp
rm *.tmp
? Question Mark – Match a Single Character
The question mark matches “exactly one” character, making it ideal for files with a fixed naming format:
# Delete file1.txt, file2.txt, fileA.txt, etc. (does not match file10.txt)
rm file?.txt
# List all two-digit logs (log01.txt through log99.txt)
ls log??.txt
# Match data_a.csv, data_b.csv... but not data_ab.csv
ls data_?.csv
[] Character Set – Match a Precise Range of Characters
# List file1.txt, file2.txt, file3.txt (excludes other numbers)
ls file[1-3].txt
# List fileA.txt, fileB.txt, fileC.txt (only uppercase A, B, C)
ls file[ABC].txt
# List .sh scripts whose names start with a lowercase letter
ls [a-z]*.sh
# Delete backups with numeric-only suffixes (bak1, bak2, bak3)
rm bak[0-9]
# Exclude numbers, list only files ending with a letter
ls file[!0-9].txt
Brace Expansion
Brace Expansion is a Bash feature that is related to Wildcards but slightly different – Wildcards “match existing files,” while Brace Expansion “generates character sequences.” It can be used to batch-create files, directories, or quickly print sequences.
Numeric Sequences
# Print 1 to 100
echo {1..100}
# Print odd numbers (step of 2)
echo {1..100..2}
# Print even numbers
echo {2..100..2}
# Print every 10th number
echo {10..100..10}
Letter Sequences
# Print a to z
echo {a..z}
# Print z to a in reverse
echo {z..a}
# Print every other letter (step of 2)
echo {a..z..2}
Batch-Creating Directories and Files
This is one of the most practical use cases for Brace Expansion:
# Create a multi-level project directory structure at once
mkdir -p project/{src,tests,docs}
# Equivalent to:
# mkdir -p project/src
# mkdir -p project/tests
# mkdir -p project/docs
# Create 10 test files at once
touch file{1..10}.txt
# Creates: file1.txt file2.txt ... file10.txt
# Create multiple monthly directories
mkdir -p logs/{2024-01,2024-02,2024-03,2024-04}
# Quickly back up (rename) a file
mv config.txt config.txt.bak
# A more concise way:
mv config.{txt,txt.bak}
Combined Usage
# Create a complete frontend project structure
mkdir -p myapp/{public/{css,js,img},src/{components,pages,utils},tests}
# Batch-create files with month prefixes
touch report_{jan,feb,mar,apr,may,jun}.csv
# Create test files with multiple extensions at once
touch test.{py,js,rb,go}
Practical Examples
Batch Deletion
# Delete all .tmp temporary files (use ls first to verify before deleting)
ls *.tmp
rm *.tmp
# Delete .log files older than 30 days
find /var/log -name "*.log" -mtime +30 -delete
# Delete all empty directories
find . -type d -empty -delete
Batch Copy (with Filters)
# Copy only image files to a backup directory
cp *.{jpg,jpeg,png,gif} /home/benz/backup/images/
# Copy all date-named reports (format like report_2024-01-01.csv)
cp report_2024-*.csv /home/benz/archive/
# Copy all scripts to another machine
scp *.sh user@remote:/home/user/scripts/
Combined with the find Command
# Find all Python scripts
find . -name "*.py"
# Find all logs and calculate total size
find /var/log -name "*.log" -exec du -sh {} \;
# Find and compress all logs older than 7 days
find /var/log -name "*.log" -mtime +7 -exec gzip {} \;
Combined with the grep Command
# Search for a specific string in all .conf configuration files
grep -r "ServerName" /etc/nginx/*.conf
# Search for function definitions in all Python files
grep -rn "def " *.py
# Recursively search for JavaScript files in all subdirectories
grep -r "console.log" --include="*.js" .
Wildcards vs Regular Expressions
Beginners often confuse Wildcards with Regular Expressions (RegEx). Although they look similar, their purposes are completely different:
| Comparison | Wildcard (Glob) | Regular Expression (RegEx) |
|---|---|---|
| Purpose | Match filenames in the Shell | Match text content |
| Tools | Shell commands like ls, cp, mv, rm | grep, sed, awk, programming languages |
Meaning of * | Any number of any characters | The preceding character appears 0 or more times |
Meaning of ? | Any single character | The preceding character appears 0 or 1 time |
Meaning of . | A literal dot (period) | Matches any single character |
Meaning of [abc] | Same (matches one character in the set) | Same |
Syntax comparison examples:
# Wildcard (Shell Glob)
# Match all .txt files
ls *.txt
# Regular Expression (grep)
# Match lines containing one or more digits
grep "[0-9]+" file.txt
# In grep, if you want . to match any character (RegEx semantics)
grep "file.txt" logs.txt # . in RegEx means "any character"
grep "file\.txt" logs.txt # To match a literal dot, you need to escape it
Frequently Asked Questions (FAQ)
Q1: What is the difference between * and **?
The standard Bash Wildcard * does not match the directory separator /, meaning *.txt only matches .txt files in the current directory and does not recurse into subdirectories.
** (double asterisk) is a feature available after enabling the globstar option in Bash 4.0+, which can recursively match directories of any depth:
# Enable the globstar option
shopt -s globstar
# ** matches .txt files in all subdirectories
ls **/*.txt
# An alternative that doesn't require globstar is to use find
find . -name "*.txt"
Q2: How do Wildcards handle filenames containing spaces?
Filenames with spaces may cause unexpected parsing issues with regular Wildcards. The recommended approach is to use quotes or find:
# If there's a file called "my document.txt"
# Wrapping the Wildcard in quotes (this prevents Shell expansion, usually not what we want)
ls "my document.txt"
# Correct approach: use find with -print0 / xargs -0 to handle spaces
find . -name "*.txt" -print0 | xargs -0 ls -l
# Or use a bash loop (safest)
for f in *.txt; do
echo "Processing: $f"
done
# Bash's for loop correctly handles filenames with spaces
Further reading: