Bash Globbing and Wildcards: Match Files Safely

Wildcard paths grouping log and backup files for safe batch selection

What You’ll Learn

In this lesson, you’ll learn how Bash uses pathname expansion, also called globbing, to match groups of files. This is useful when working with log files, backup archives, and other files that follow naming patterns.

  • Use *, ?, and character ranges in file patterns.
  • Preview the files a pattern matches before running a batch command.
  • Use matched filenames safely in a Bash loop.
  • Avoid common quoting and unmatched-pattern mistakes.
Ad

The Concept

Globbing is Bash’s process of expanding a wildcard pattern into matching pathnames before a command runs. For example, if a directory contains server.log and worker.log, the pattern *.log matches both files.

The most common wildcard characters are:

  • * matches zero or more characters.
  • ? matches exactly one character.
  • [abc] matches one character from the listed characters.
  • [0-9] matches one character in the specified range.

For example, app-*.log can match every log file whose name begins with app- and ends with .log. The pattern is not a regular expression. It is a filename pattern handled by the shell.

Globbing is useful for batch operations because you can select a group of files without typing every filename. Always preview a pattern before using it with a command that changes or deletes files.

Basic Example

The following script creates a temporary folder containing sample logs and backups. It then uses two glob patterns to display the matching groups.

#!/usr/bin/env bash
set -e

demo_dir=$(mktemp -d)
trap 'rm -rf "$demo_dir"' EXIT

cd "$demo_dir"
touch app-2026-08-18.log app-2026-08-19.log
touch backup-2026-08-18.tar.gz backup-2026-08-19.tar.gz
touch notes.txt

printf 'Log files:\n'
printf '%s\n' app-*.log

printf '\nBackup files:\n'
printf '%s\n' backup-*.tar.gz

Expected Output

The temporary directory has a random name, but the matched filenames are predictable:

Log files:
app-2026-08-18.log
app-2026-08-19.log

Backup files:
backup-2026-08-18.tar.gz
backup-2026-08-19.tar.gz

How the Code Works

A process diagram showing Bash receiving an unquoted wildcard pattern, expanding it into matching filenames, and then passing those filenames to a batch operation. If no files match, the pattern may remain literal, so the matches should be previewed before a changing command runs.
Bash expands an unquoted glob into matching pathnames before the command executes; preview the results and handle unmatched patterns cautiously.
  • mktemp -d creates a temporary directory and stores its path in demo_dir.
  • trap 'rm -rf "$demo_dir"' EXIT removes the temporary directory when the script finishes.
  • touch creates empty sample files for the demonstration.
  • app-*.log matches filenames beginning with app- and ending with .log.
  • backup-*.tar.gz matches filenames beginning with backup- and ending with .tar.gz.

When Bash reaches printf '%s\n' app-*.log, it expands the pattern first. The command that actually runs is effectively:

printf '%s\n' app-2026-08-18.log app-2026-08-19.log

The quotes around "$demo_dir" protect the directory path if it contains spaces. The wildcard itself remains outside the quotes so Bash can expand it. Quoting the entire pattern, such as "$demo_dir/*.log", would prevent globbing.

Another Example

Character patterns can select a narrower group. This example copies only the January, February, and March backups into a review directory. The pattern backup-2026-0[1-3].tar.gz matches a month digit from 1 through 3.

#!/usr/bin/env bash
set -e

demo_dir=$(mktemp -d)
trap 'rm -rf "$demo_dir"' EXIT

cd "$demo_dir"
mkdir selected
touch backup-2026-01.tar.gz backup-2026-02.tar.gz
touch backup-2026-03.tar.gz backup-2026-04.tar.gz
touch backup-2026-11.tar.gz

for backup in backup-2026-0[1-3].tar.gz; do
    cp "$backup" selected/
done

printf 'Backups selected for review:\n'
printf '%s\n' selected/*

The loop receives one matching pathname at a time. The variable is quoted in cp "$backup" selected/, which safely handles filenames containing spaces. The files from April and November are not copied because their month portions do not match 0[1-3].

Common Mistakes

Quoting the wildcard

Do not quote the wildcard when you want Bash to expand it:

printf '%s\n' "*.log"

This prints the literal text *.log instead of matching log files. Quote variables and individual filenames, but leave the wildcard portion unquoted.

Using ls to feed a loop

Avoid constructing loops with command output such as for file in $(ls *.log). Filenames containing spaces can be split incorrectly. Use the glob directly:

for file in *.log; do
    printf 'Reviewing: %s\n' "$file"
done

Forgetting to preview a destructive command

Before using a pattern with rm, mv, or another changing command, first print the matches. A pattern that is broader than expected can affect more files than intended.

Assuming every pattern always matches

If no filename matches a pattern, Bash commonly passes the pattern itself to the command. For example, printf '%s\n' missing-*.log may print missing-*.log. Check the directory contents before performing a batch operation.

Try It Yourself

Create a folder containing these files:

  • app-error-2026-08-18.log
  • app-error-2026-08-19.log
  • app-info-2026-08-18.log
  • backup-2026-08.tar.gz
  • backup-2026-09.tar.gz
  • readme.txt

Write Bash commands that print only the error logs and then print only the two-digit backups. Use app-error-*.log for the first group and backup-2026-??.tar.gz for the second group.

Challenge

Build a small script that simulates a daily archive review:

  • Create a temporary directory with three error logs, two information logs, and two backup archives.
  • Print only the error logs using a glob.
  • Print only the backup archives using a glob with ?.
  • Use a for loop to print each selected backup with the label Reviewing:.

Do not use ls to create either file list.

Solution

#!/usr/bin/env bash
set -e

demo_dir=$(mktemp -d)
trap 'rm -rf "$demo_dir"' EXIT

cd "$demo_dir"
touch app-error-2026-08-18.log app-error-2026-08-19.log
touch app-error-2026-08-20.log app-info-2026-08-18.log
touch app-info-2026-08-19.log
touch backup-2026-08.tar.gz backup-2026-09.tar.gz

printf 'Error logs:\n'
printf '%s\n' app-error-*.log

printf '\nBackup archives:\n'
for backup in backup-2026-??.tar.gz; do
    printf 'Reviewing: %s\n' "$backup"
done

The first pattern selects only filenames beginning with app-error-. The second pattern uses two question marks, so it selects backup filenames with exactly two characters after backup-2026-. The loop handles each matched backup separately and quotes the variable when printing it.

Key Takeaways

  • Bash globbing expands wildcard patterns into matching pathnames before a command runs.
  • Use * for zero or more characters, ? for one character, and brackets for a character set or range.
  • Leave the wildcard unquoted so it can expand, but quote variables when using the resulting filenames.
  • Preview matches before running commands that move, copy, or delete files.
  • Use a direct glob in a for loop instead of parsing the output of ls.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top
Ad
Ad
Ad