Kahibaro
Discord Login Register

Wildcards and globbing

Wildcards and globbing let you use patterns instead of typing exact filenames on the command line. The shell expands these patterns before running the command, turning them into a list of matching paths.

This chapter focuses on how to write and use those patterns.

What “globbing” means

Example:

If a pattern matches nothing, behavior depends on the shell and settings (more on that later).

Basic wildcards

`*` — match “anything”

* matches zero or more characters (except /).

Common uses:

Examples:

# List all .txt files
ls *.txt
# Copy all JPEG photos
cp *.jpg *.jpeg ~/Pictures/
# Remove all .log files in current directory
rm *.log

Remember: * does not cross directory boundaries; it won’t match /.

`?` — match a single character

? matches exactly one character (except /).

Examples:

# Show PNG files with 3-character names
ls ???.png
# Match exactly one character between prefix and suffix
ls report-?.pdf

Character classes: `[...]`

Square brackets [...] match one character from a set or range.

Basic forms:

Examples:

# Files named file1.txt, file2.txt, file3.txt
ls file[123].txt
# Images numbered 0-9
ls img[0-9].png
# Files starting with any letter, then .txt
ls [A-Za-z].txt

A hyphen - inside [] means a range if placed between characters, like a-z. Put - at the start or end if you need a literal -, e.g. [-abc] or [abc-].

Negated classes: `[^...]`

[^...] matches any single character not in the set.

Examples:

# Everything that does NOT start with dot
ls [^.]*
# All .log files whose names do not start with 'a'
ls [^a]*.log

Matching hidden files

On Linux, filenames starting with . are hidden. Wildcards like * and ? do not match them by default.

Examples:

To include hidden files explicitly:

Some tools (like bash with certain options, or file managers) can change this behavior, but the default is: * ignores dotfiles.

Globbing and directories

Wildcards can be used in directory names too.

Examples:

# List all items in any directory that starts with "logs"
ls logs*/
# Copy all .png files from all user directories: /home/*/Pictures
cp /home/*/Pictures/*.png /backup/pictures/
# List all .conf files in any subdirectory of /etc whose name ends with 'd'
ls /etc/*d/*.conf

Notes:

Brace expansion vs globbing

Brace expansion looks similar to globs but is different. It creates strings from a pattern and does not depend on filesystem contents.

Examples:

# Brace expansion - produces literal names
echo file{1,2,3}.txt
# -> file1.txt file2.txt file3.txt
# Globbing - matches existing files
echo file*.txt

Key points:

You can combine them:

# Copy both .jpg and .png files
cp *.{jpg,png} /backup/images/

Here, .{jpg,png} becomes .jpg .png, and then each is globbed.

Escaping wildcards to use them literally

Sometimes you want a literal * or ? in a command (e.g. matching text inside a file, not filenames).

You can prevent globbing by:

  1. Quoting the pattern:
    • '*.txt'
    • "data?.csv"
  2. Escaping special characters with backslash \:
    • \*, \?, \[, \]

Examples:

# Search for the literal string "*.log" inside files
grep "*.log" notes.txt
# Create a file literally named "data*.txt"
touch 'data*.txt'
# Show a pattern without expanding it
echo \*.txt

Inside single quotes, * and ? lose their special meaning completely.

Combining patterns

You can mix *, ?, and [...] to build precise matches.

Examples:

# Files that start with "log-", then 4 digits, then ".txt"
ls log-????.txt
# config-1.conf, config-2.conf, config-A.conf but not config-10.conf
ls config-[0-9A-Z].conf
# Files that start with 'backup-' and end in .tar.gz or .tgz
ls backup-*.tar.gz backup-*.tgz
# Photos from 2023 January – March, day 01-09
ls photo-2023-0[1-3]-0[1-9].jpg

You can also use multiple globs in a single command:

# Remove both .tmp and .bak files
rm *.tmp *.bak

Recursive globs: `**` (bash extended globstar)

Some shells support a special pattern ** that matches directories recursively when enabled.

In bash, you must turn it on:

shopt -s globstar

Then:

Examples:

# List all .py files under current directory tree
shopt -s globstar
ls **/*.py
# Copy all .conf files from /etc and all subdirectories
shopt -s globstar
cp /etc/**/*.conf /backup/etc-configs/

Without globstar, ** is treated like * (non-recursive).

When globs match nothing

What happens if a pattern matches no files depends on shell settings.

Common behaviors:

  ls *.nope
  # ls: cannot access '*.nope': No such file or directory
  shopt -s nullglob
  echo *.nope
  # (prints nothing)

Be aware of this when writing scripts; patterns that match nothing can cause surprising results.

Safety tips (especially with `rm`)

Wildcards are powerful—and dangerous—when deleting.

Guidelines:

  1. Always test with ls first:
   # Check what will be removed
   ls *.log
   # Then, if it looks correct:
   rm *.log
  1. Avoid running destructive commands from the wrong directory. Use absolute or explicit paths:
   rm /var/log/*.log
  1. Be extra careful with * after rm:
    • rm * – deletes everything (non-hidden) in current directory.
    • rm -rf * – deletes everything recursively; a typo here can be catastrophic.
  2. Consider using interactive mode while learning:
   rm -i *.log

rm -i asks for confirmation for each file.

Practical examples

A few common real-world patterns:

# Delete all temporary files ending with ~
rm *~
# Archive log files with date in the name, e.g., app-2023-01-01.log
tar czf logs.tar.gz app-2023-*.log
# Move all PDFs and images to Documents
mv *.{pdf,PDF,jpg,jpeg,png} ~/Documents/
# List only directories (using trailing slash)
ls -d */
# Delete all files whose names start with a digit
rm [0-9]*
# List all ".conf" files in /etc and one level of subdirectories
ls /etc/*.conf /etc/*/*.conf

Understanding wildcards and globbing allows you to interact efficiently with large numbers of files using concise patterns, rather than typing each filename individually.

Views: 27

Comments

Please login to add a comment.

Don't have an account? Register now!