Globbing for only files in Bash
Categories:
Globbing for Only Files in Bash: A Comprehensive Guide

Learn how to effectively use Bash globbing patterns to select only files, excluding directories, symlinks, and other file types, ensuring precise command execution.
Bash globbing is a powerful feature that allows you to specify sets of filenames using wildcard characters. While commonly used to match both files and directories, there are often scenarios where you need to target only regular files. This article will guide you through various techniques to achieve precise file-only globbing in Bash, enhancing the reliability and safety of your shell scripts and command-line operations.
Understanding Basic Globbing Behavior
By default, glob patterns like *
or *.txt
will match both files and directories that fit the pattern. This can be problematic when commands are designed to operate exclusively on files, such as cat
, grep
, or mv
(when moving to a new name, not into a directory). Executing such commands on directories can lead to errors, unexpected behavior, or even data loss.
mkdir my_dir
touch file1.txt file2.log
# This will list both files and the directory
ls *
# This will attempt to 'cat' the directory, resulting in an error
cat *
Default globbing behavior matching files and directories
Using find
for Robust File Selection
For more complex or robust scenarios, especially when dealing with subdirectories or specific file properties, the find
command is often the most reliable tool. It offers extensive filtering capabilities that go beyond simple globbing.
# Find only regular files in the current directory
find . -maxdepth 1 -type f
# Find only regular files and execute a command on them
find . -maxdepth 1 -type f -exec ls -l {} \;
# Using xargs for efficiency with many files
find . -maxdepth 1 -type f -print0 | xargs -0 cat
Using find
to select only regular files
flowchart TD A["Start: Need to process files only"] --> B{Globbing or `find`?} B -->|Simple case, current dir| C["Use `GLOBIGNORE` or `extglob`"] B -->|Complex, subdirs, specific types| D["Use `find` command"] C --> C1["Set `GLOBIGNORE='*:*'`"] C --> C2["Enable `extglob` and use `!(*/)`"] C1 --> E["Process files"] C2 --> E["Process files"] D --> D1["Specify `-type f` for files"] D --> D2["Combine with `-maxdepth`, `-name`, etc."] D1 --> E["Process files"] D2 --> E["Process files"] E --> F["End: Files processed safely"]
Decision flow for selecting file-only globbing methods
Bash Globbing Options for File-Only Selection
Bash provides several built-in mechanisms to refine globbing behavior. These are generally more efficient for simple cases within the current directory compared to external commands like find
.
echo
) before using them with destructive commands like rm
or mv
.Method 1: Using GLOBIGNORE
The GLOBIGNORE
shell variable allows you to specify a colon-separated list of patterns to exclude from globbing matches. To exclude directories, you can set GLOBIGNORE
to match anything ending with a slash, which typically denotes a directory.
mkdir dir1 dir2
touch fileA.txt fileB.log
# Set GLOBIGNORE to exclude directories
GLOBIGNORE='*:*'
# Now, '*' will only match files
ls *
# Unset GLOBIGNORE to revert to default behavior
unset GLOBIGNORE
Using GLOBIGNORE
to exclude directories
GLOBIGNORE
. It affects all subsequent globbing until unset or changed. It also hides dotfiles by default, unless explicitly included in the pattern.Method 2: Using extglob
with Pattern Matching
Bash's extglob
option enables extended pattern matching operators, similar to regular expressions. This allows for more sophisticated exclusions directly within the glob pattern.
mkdir folder1 folder2
touch doc1.pdf doc2.txt
# Enable extended globbing
shopt -s extglob
# Match everything EXCEPT directories (patterns ending with /)
ls !(*/*)
# Another common pattern to exclude directories
ls !(*/*|*/)
# Disable extended globbing
shopt -u extglob
Using extglob
to exclude directories from glob matches
Method 3: Looping with Conditional Checks
For maximum control and clarity, especially within scripts, iterating through all matches and performing a conditional check (-f
for regular file) is a very reliable method.
mkdir test_dir
touch test_file.txt
for item in *;
do
if [ -f "$item" ]; then
echo "Processing file: $item"
# Your command here, e.g., cat "$item"
fi
done
Looping through glob matches and checking if they are regular files
-f
test in [ -f "$item" ]
checks if $item
exists and is a regular file. Other useful tests include -d
for directories, -L
for symbolic links, and -s
for non-empty files.