DEV Community

NJEI
NJEI

Posted on

Mastering Wildcards in Linux: *, ?, and [] for Efficient File Management

The Problem

You need to delete 50 log files. Do you run rm 50 times? Move 100 images—one by one?

Wildcards solve this. They let you match multiple files with a single pattern.

What Are Wildcards?

Wildcards are special characters that represent patterns in filenames.

The three main wildcards:

  • * - Matches zero or more characters
  • ? - Matches exactly one character
  • [] - Matches a range of characters

The Asterisk (*): Match Everything

The * matches zero or more characters.

Basic Usage

# List all files starting with "abc"
ls abc*
# Matches: abc, abc123, abc-file.txt, abcdefg

# Delete all .tmp files
rm *.tmp
# Matches: data.tmp, backup.tmp, cache.tmp

# Find files containing "xy"
rm *xy*
# Matches: xyfile, file-xy-data, xy, data-xy.txt
Enter fullscreen mode Exit fullscreen mode

Real-World: Cleaning Log Files

You have hundreds of logs in /var/log/app/:

app-2024-11-01.log
app-2024-11-02.log
...
app-2024-11-30.log
Enter fullscreen mode Exit fullscreen mode

Delete all November logs:

rm /var/log/app/app-2024-11-*.log
Enter fullscreen mode Exit fullscreen mode

Compress before archiving:

gzip /var/log/app/app-2024-11-*.log
Enter fullscreen mode Exit fullscreen mode

The Question Mark (?): Match One Character

The ? matches exactly one character—no more, no less.

Basic Usage

# Match files with one char before "abc-xyz"
ls ?abc-xyz*
# Matches: 1abc-xyz, 2abc-xyz, xabc-xyz
# NOT: abc-xyz, 10abc-xyz

# Match single-character files
ls ?
# Matches: a, 1, x
# NOT: ab, 123

# Match specific patterns
ls file-?.txt
# Matches: file-1.txt, file-a.txt
# NOT: file-10.txt, file.txt
Enter fullscreen mode Exit fullscreen mode

Real-World: Finding Backup Versions

Your backups:

backup-1.tar.gz
backup-2.tar.gz
...
backup-9.tar.gz
backup-10.tar.gz
Enter fullscreen mode Exit fullscreen mode

List only single-digit backups:

ls backup-?.tar.gz
# Shows: backup-1.tar.gz through backup-9.tar.gz
# Excludes: backup-10.tar.gz
Enter fullscreen mode Exit fullscreen mode

Square Brackets ([]): Match Ranges

The [] matches any single character within the brackets.

Basic Usage

# Match files starting with "c" or "d"
ls -l [cd]*
# Matches: cat.txt, dog.log, config.yml
# NOT: apple.txt, bat.sh

# Match files starting with any digit
ls [0-9]*
# Matches: 1file.txt, 2data.log, 9report.pdf
# NOT: file1.txt (doesn't start with digit)

# Match specific characters
ls file[123].txt
# Matches: file1.txt, file2.txt, file3.txt
# NOT: file4.txt

# Match letter ranges
ls [a-f]*
# Matches files starting with: a, b, c, d, e, f
Enter fullscreen mode Exit fullscreen mode

Real-World: Organizing Project Files

Your project structure:

config-dev.yml
config-prod.yml
config-test.yml
data-dev.csv
data-prod.csv
data-test.csv
Enter fullscreen mode Exit fullscreen mode

List only dev and test files (not production):

ls *-[dt]*
# Matches: config-dev.yml, config-test.yml, data-dev.csv, data-test.csv
# Excludes: config-prod.yml, data-prod.csv
Enter fullscreen mode Exit fullscreen mode

Brace Expansion ({}): Create Multiple Files

Not a wildcard, but incredibly useful.

Basic Usage

# Create 9 files
touch abc{1..9}-xyz
# Creates: abc1-xyz, abc2-xyz, ..., abc9-xyz

# Create files with different extensions
touch file.{txt,log,bak}
# Creates: file.txt, file.log, file.bak

# Create numbered directories
mkdir project-{001..010}
# Creates: project-001, project-002, ..., project-010
Enter fullscreen mode Exit fullscreen mode

Real-World: Test Environment Setup

# Create 100 test CSV files
touch test-data-{001..100}.csv

# Create directory structure
mkdir -p {dev,test,prod}/{logs,config,data}
# Creates: dev/logs, dev/config, dev/data, test/logs, etc.
Enter fullscreen mode Exit fullscreen mode

Special Characters

Backslash (): Escape Characters

Match files with wildcard characters in their names:

# Match file literally named "file*.txt"
ls file\*.txt
# Matches: file*.txt (actual filename with asterisk)

# Match files with spaces
ls my\ file.txt
# Or use quotes
ls "my file.txt"
Enter fullscreen mode Exit fullscreen mode

Dollar Sign ($): Variables

Reference variables:

# Use variable in command
USER_DIR=/home/ubuntu
ls $USER_DIR/*.txt
# Expands to: ls /home/ubuntu/*.txt

# Current user's home
ls $HOME/documents
# Same as: ls ~/documents
Enter fullscreen mode Exit fullscreen mode

Using man for Documentation

Every command has a manual:

man ls
# Shows complete documentation
Enter fullscreen mode Exit fullscreen mode

Navigate man pages:

  • Space - Scroll down
  • b - Scroll up
  • / - Search
  • q - Quit

Quick help:

ls --help
# Brief usage summary
Enter fullscreen mode Exit fullscreen mode

Combining Wildcards

Wildcards are powerful when combined:

# Match all .log files from November or December
ls app-2024-1[12]-*.log
# Matches: app-2024-11-01.log, app-2024-12-15.log

# Delete temp files with single-char extensions
rm temp-*.?
# Matches: temp-data.1, temp-file.x
# NOT: temp-data.txt (3 chars)

# Copy specific backup files
cp backup-[1-5]?.tar.gz /archive/
# Matches: backup-10.tar.gz through backup-59.tar.gz
Enter fullscreen mode Exit fullscreen mode

Common Mistakes

❌ Mistake #1: Not quoting wildcards with find

# Wrong - shell expands * before find sees it
find . -name *.txt

# Right - quote to pass literal * to find
find . -name "*.txt"
Enter fullscreen mode Exit fullscreen mode

❌ Mistake #2: Using * when you need ?

# Too broad
ls file-*.txt
# Matches: file-1.txt, file-10.txt, file-abc.txt

# More specific
ls file-?.txt
# Matches only: file-1.txt, file-a.txt
Enter fullscreen mode Exit fullscreen mode

❌ Mistake #3: Not testing before deleting

# DANGEROUS - always check first
ls *.tmp  # Verify what will be deleted
rm *.tmp  # Then delete

# Or use -i flag for confirmation
rm -i *.tmp
Enter fullscreen mode Exit fullscreen mode

Practical Examples

Clean build artifacts

# Remove compiled files
rm *.o *.class *.pyc

# Remove all files in current directory
rm ./*
Enter fullscreen mode Exit fullscreen mode

Find and process files

# Count lines in all Python files
wc -l *.py

# Search in all config files
grep "database" *.conf

# Copy all images to backup
cp *.{jpg,png,gif} /backup/images/
Enter fullscreen mode Exit fullscreen mode

Batch rename

# Rename .txt to .bak
for file in *.txt; do
    mv "$file" "${file%.txt}.bak"
done
Enter fullscreen mode Exit fullscreen mode

Quick Reference

Wildcard Matches Example Result
* Zero or more chars abc* abc, abc1, abc-file
? Exactly one char ?abc 1abc, xabc
[] Char in brackets [abc]* apple, bat, cat
[a-z] Range [a-z]* lowercase start
[0-9] Digits file[0-9].txt file0.txt-file9.txt
{} Brace expansion {1..5} 1 2 3 4 5

Advanced Patterns

Exclude patterns

# List all files except .txt
ls !(*.txt)
# Requires: shopt -s extglob
Enter fullscreen mode Exit fullscreen mode

Multiple wildcards

# Match complex patterns
ls [a-z]*[0-9].{log,txt}
# Matches: app1.log, data5.txt, test9.log
Enter fullscreen mode Exit fullscreen mode

Case-insensitive matching

# Enable case-insensitive globbing
shopt -s nocaseglob
ls *.TXT  # Also matches .txt, .Txt, .TxT
Enter fullscreen mode Exit fullscreen mode

Performance Tips

Be specific

# Slower - searches everywhere
ls *file*

# Faster - more specific pattern
ls file-*.log
Enter fullscreen mode Exit fullscreen mode

Use quotes when needed

# Shell expands first (can be slow with many files)
echo *

# Faster for large directories
echo "*"
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  1. * matches zero or more - Broadest pattern
  2. ? matches exactly one - Precise matching
  3. [] matches ranges - Specific character sets
  4. {} creates multiple items - File creation tool
  5. Test with ls before rm - Always verify
  6. Quote when needed - Prevent unwanted expansion
  7. Read man pages - Detailed documentation

Wildcards turn repetitive operations into single commands. Master these and you'll work exponentially faster.


What's your most useful wildcard pattern? Share in the comments!

Follow for more practical Linux tips as I document my journey into cloud engineering and DevOps.

Top comments (0)