Complete Guide to Linux Wildcards: How to Use *, ?, and [] Glob Patterns

2024/01/04

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

WildcardNameDescriptionExampleMatches
*AsteriskMatches any number of any characters (including zero characters)*.txta.txt, readme.txt, hello.txt
?Question markMatches exactly one characterfile?.txtfile1.txt, fileA.txt (does not match file10.txt)
[abc]Character setMatches any single character within the bracketsfile[123].txtfile1.txt, file2.txt, file3.txt
[a-z]Character rangeMatches any single character within the specified rangefile[a-z].txtfilea.txt, fileb.txt, …filez.txt
[!abc]Negated character setMatches any single character not in the bracketsfile[!0-9].txtfilea.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:

ComparisonWildcard (Glob)Regular Expression (RegEx)
PurposeMatch filenames in the ShellMatch text content
ToolsShell commands like ls, cp, mv, rmgrep, sed, awk, programming languages
Meaning of *Any number of any charactersThe preceding character appears 0 or more times
Meaning of ?Any single characterThe 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: