Glob Expansion in Bash

Glob expansion is one of the elegant techniques in Bash to find files or match pathnames. There are a few special characters to execute the technique efficiently such as “*”, “?” and “[” etc. In this article, I will talk about the use of those characters as well as various aspects of glob expansion in Bash.

What is Glob Expansion in Bash?

Glob expansion, also known as globbing, is a way to match filename or pathname in the Linux operating system. It allows users to use wildcard characters to match a desired pattern while searching for filenames or pathnames. It is a quick and efficient technique to find files and navigate directories. The most common wildcards used for globbing are “*”, “?”, “[”. Whenever Bash finds these characters unquoted, it tries to replace those with filenames matching the pattern defined by the wildcards. For example, “file.???” can match a filename like “file.txt” or “file.png” as “?” wildcard is used for single character matching.

Glob Expansion Using Different Wildcards in Bash

There are a couple of wildcard characters widely used for globbing in Bash. Those wildcards may look similar to regular expressions. However, these are inherently different from regular expression. The list below contains a few wildcard characters frequently used for globbing.

  1. * (Asterisk)
  2. ? (Question Mark)
  3. [ ] (Square Bracket)
  4. ! (Exclamation Mark)
  5. | (pipe)

1. Glob Expansion of Matching Any Character Using “*” (Asterisk)

Asterisk *” is a powerful and widely used wildcard for globbing. It can match any length of characters including none.  For instance, “*.txt” can match  “file.txt”, “f.txt” or just “.txt”. Check the below script.

#!/bin/bash

echo "Matching text files:"

for file in *.txt; do
    echo "$file"
done

The script employs a for loop to iterate through all the files in the current directory that match the glob pattern “*.txt”. For each matching file, the script echoes its name in the terminal.

Asterisk for glob expansion in Bash

When I execute the program in my terminal, four files match the pattern. If you closely look at those, each of the files has a “.txt” extension. From the matching filenames it is evident that an asterisk sign matches with strings of various lengths.

NOTE: Glob expansion can match hidden files starting with a dot. To do so, include the dot as a literal in the pattern, like “.b*“, to match files such as “.bashrc“. However, if the shell option globskipdots is enabled, filenames with “.” or “..” will never be matched.

2. Glob Expansion of Matching a Single Character Using the “?” Sign

The “?” (question mark) is a glob expansion that matches with a single character in Bash globbing. For example, “user?.txt” can match with “user1.txt” or “users.txt” or any other character in place of the question mark. Look at the script below to see the execution.

#!/bin/bash

echo "Matching text files:"

for file in user?.txt; do
    echo "$file"
done

The program uses a for loop to iterate through all the files in the current directory that match the glob pattern “user?.txt”. Here, the “?” wildcard is used to match a single character. For each matching file, the script echoes its name in the terminal.

Question mark for matching single character in Bash

While running the program in the terminal, the “user?.txt” matches with the filename “users.txt” where the question mark represents the single character “s”.

3. Glob Expansion Using Square Bracket “[ ]” in Bash

A [] (square bracket) is used to match a single character within the defined set of characters or ranges. For instance, the expression [a-c] will match any one of the characters a, b or c. However, it will not match the sequence ab because it’s designed to match a single character. Additionally, it will not match the character d since it is not included in the expression defined within the square brackets. Let’s see how to use it in a script.

#!/bin/bash

echo "Matching Directories:"

for dir in [p-xP-X]*; do
    if [ -d "$dir" ]; then
        ls -d "$dir"
    fi
done

The program displays directories within the current folder that have names starting with a letter in the range from “p” to “x” (both lowercase and uppercase). It iterates through the contents of the current folder, matching directory names that satisfy the pattern [p-xP-X]* using a for loop. For each matching, it checks if it is a directory using the conditional statement [ -d "$dir" ]. Then ls command with the “-d” option displays the directory’s name.

Range for matching pattern in Bash using square bracket

Upon execution, the program successfully prints directory names that start with characters falling within the range of “p” to “x” both in uppercase and lowercase.

Here’s the ranges that can be used within square brackets for matching glob patterns.

Range Explanation Example Sample Output
[:digit:] Match any digit file[0-9].txt file1.txt or file5.txt
[:alpha:] Match any uppercase or lowercase letters. file[A-Z].txt filea.txt or fileA.txt
[:alnum:] Match any alphanumeric characters [a-zA-z0-9] file1.txt or fileA.txt or filea.txt

Negating a Pattern in Glob Expansion

Negating a pattern means it can match anything except what is specified in the pattern. The caret (^) sign and exclamation mark are often used to negate a glob pattern.

Negating a Range Using Caret “^” in Glob Expansion

The caret (^) sign is used to negate a range of pattern. For example, [ab] matches either the character a or b while [^ab] will match any character except a and b. Here’s how to use it:

!/bin/bash
: '
List files or directories that
do not start with c-z or C-Z'
for file in [^c-zA-Z]*.sh; do
echo "$file"
done

This script uses the pattern [^c-zA-Z]*.sh which means any file not starting with c-z and A-Z.

Negating a pattern using caret sign in Bash

The image shows that the program finds the files of the current directory that do not start with any character from c to z (lowercase) or any character from A to Z (uppercase).

Exclamation sign (!) in place of caret (^) can yield a similar result. 

Negating a Pattern Using Exclamation “!” in Glob Expansion

One can use an exclamation mark as well to negate a pattern. To do this effectively, it’s required to enable extended globbing using shopt -s extglob command.

#!/bin/bash

shopt -s extglob  # Enable extended globbing

# Files except those ending with .txt or .sh

for file in !(*.sh|*.txt); do
if [ -f "$file" ]; then
echo "$file"
done

This script with extended globbing enabled, lists files in the current directory that do not end with either “.txt” or “.sh“. It achieves this by using a for loop with !(*.sh|*.txt) to match files with names that don’t have these extensions. The script then checks if each matched item is a file using the conditional statement [ -f "$file" ] before echoing their names.

Negating a glob pattern using exclamation

The image shows that the script displays the files of the current directory that don’t have “.txt” or “.sh” extension.

Brace Expansion for Matching with Multiple Entities

Anything put inside unquoted curly braces is expanded and treated differently to the Bash shell. This Brace expansion is one of the shell expansion techniques in Bash. Globbing with brace expansion is so powerful. It can be used for matching files with different extensions at a time. Here’s an example:

#!/bin/bash
# Files with .txt or .png extension
ls -lh *.{txt,png}

This Bash script lists and displays detailed information about files with either with a “.txt” or “.png” extension in the current directory. It uses curly braces or the brace expansion to match multiple entities at a time.

Negating a glob pattern using exclamation

The image shows that the program lists multiple files with a “.txt” extension. But It doesn’t find any files with a “.png” extension.

Tab Completion to Match Glob Pattern

Tab completion is the fastest way to complete file names in your current directory. The TAB key can find and match with the filename when a part of it is written.

Let’s say I have a file called “find_replace.txt” in the current directory. After writing a substantial portion of the filename (say “find_”), pressing  TAB expands the whole name.

Tab completion to match filenames

After pressing TAB, I get the full filename as shown in the image below.

Result of Tab completion for matching filename in Bash

Recursive Globbing Using “globstar”

The globstar is an option that allows users to search not only within the current directory but also recursively through all its subdirectories. This means it looks for matches in the current directory and all its nested folders. For instance, the ls **/*.txt command should look for the pattern “*.txt”  in the current directory and at all levels of subdirectories below the current directory. First, run this command and look at the output before enabling globstar.

Recursive globbing result without enabling globstar

As you can see, no file or directory matched with the pattern. Now, run the following command to enable globstar.

shopt -s globstar

Again, run ls **/*.txt command and see the differences.

Recursive globbing after enabling globstar

This time, the command found multiple matches on my computer. If you examine “Documents/backup/cloud/file1.txt“, you’ll notice that the command searched for files and directories, including all their subdirectories, within the current directory.

Glob Expansion with Whitespaces

Glob expansion may not work properly for filenames or pathnames that contain whitespace. For example, a  file named “my file.txt” can’t be listed using the ls command. It will end up with an error due to the whitespace.Globbing of filename with whitespacesThe best way to deal with this problem is to set the Internal Field Separator (IFS) so that it can remove all the while whitespaces. The script shows how to use it:

IFS="$(printf '\n\t')"   # Remove space.

#  Correct glob use:
for file in *file.txt ; do
if [ -e $file ] ; then   # Check whether the file exists.
ls -l $file
fi
done

The script sets the Internal Field Separator (IFS) to remove spaces, tabs, and newlines. It then utilizes a for-loop to iterate through files in the current directory that match the pattern “*file.txt” For each file, it checks if the file exists using -e option in the condition. If the file exists, it runs the ls -l command to display detailed information about the file.

Glob expansion with whitespaces using IFS variable

As shown in the image, the script lists “my file.txt” though it has a whitespace within its name.

How to Disable Glob Expansion

Disable globbing using set -f to prevent wildcard characters from being interpreted as part of glob expansion, . This is really useful when working with filenames or path names that contain wildcard characters. If it is required to enable it again use set +f.

However, when you use set -f to disable file globbing, variable settings are lost once the shell session ends. To address this, you can save the shell settings to a variable and later restore the settings using that variable.

#!/bin/bash

# Save the current shell options
shell_opts=$(set +o)
# Disable globbing
set -f
# Your code here without globbing
echo *.txt
# Restore shell options
eval "$saved_opts"

The script begins by capturing the current shell options and storing them in the variable “shell_opts”. It then disables globbing, preventing wildcard characters “*” from being expanded. The “echo *.txt” command is used to illustrate this; it will print the literal string “*.txt” since globbing is turned off. Finally, it attempts to restore the original shell options using eval.

When you run the program in the terminal, it will print the literal “*.txt” as shown in the image.Temporarily disable glob expansionHowever, when you run the command echo *.txt in the terminal the asterisk wildcard will be expanded if it finds any match like the following.

Result of glob expansion without disabling it

Conclusion

To conclude, glob expansion is frequently useful to the users of Bash shell. One can’t harness its full effectiveness without having a complete idea. I believe this article helped you to implement Glob Expansion at least in some obvious circumstances.

People Also Ask

Is the exclamation sign part of Globbing or Regular Expression in Bash?

Both. The exclamation works both in globbing and regular expression. In glob patterns, the exclamation mark is used to negate a pattern. For example, if you want to match all files except those with a ‘.txt’ extension, you can use ‘!(*.txt)‘.

Similarly, in the context of globbing the exclamation mark is used to negate a pattern in the case of regular expression as well. ‘[!ab]‘ will match any character except ‘a‘ or ‘b‘.

How can I turn off ‘globstar’ option in the Bash shell?

To turn off  the globstar option in the Bash shell, use the shopt -u globstar command. This command turns off the globstar option, preventing recursive searching through subdirectories.

How to perform globbing within parameter expansion in Bash

To perform globbing within parameter expansion write the globbing pattern properly, make sure there is no syntax error. Suppose you want to use parameter expansion to access files that match a certain glob pattern like ‘*.txt‘. You can use $(…) to execute a command within parameter expansion and perform globbing.

matching_files=($(echo “*.txt”))

How does glob expansion with ‘[‘ differ from the ‘[[…]]’ syntax?

[‘ is primarily used for pattern matching or pathname expansion and the double square bracket is used to evaluate a condition,  For example, ‘[aeiou]‘ matches any vowel. On the other hand, ‘[[ $var -gt 10 ]]‘ will check whether the ‘var‘ is greater than 10.

Related Articles


<< Go Back to An Overview of Shell Expansion in Bash | Bash Scripting Tutorial 

4.8/5 - (5 votes)
LINUX
FUNDAMENTALS
A Complete Guide for Beginners Enroll Course Now
Md Zahidul Islam Laku

Hey, I'm Zahidul Islam Laku currently working as a Linux Content Developer Executive at SOFTEKO. I completed my graduation from Bangladesh University of Engineering and Technology (BUET). I write articles on a variety of tech topics including Linux. Learning and writing on Linux is nothing but fun as it gives me more power on my machine. What can be more efficient than interacting with the Operating System without Graphical User Interface! Read Full Bio

Leave a Comment