1. Overview

Globbing is a feature of many shells that enables us to match multiple files with a single pattern. Further, globbing is useful when we want to operate on a set of files that share some common characteristics.

However, sometimes we may want to exclude a certain pattern from a glob match. For instance, we may want to list all files in a directory except for the hidden ones, or we may want to delete all files with a certain prefix, except one.

In this tutorial, we’ll learn how to facilitate this exclusion using different methods and techniques. We’ll focus on Bash, one of the most popular and widely used shells. Yet, some of these options may also work in other shells.

2. Basic Syntax and Examples of Globbing

Globbing is based on the use of special characters called wildcards. Wildcards can represent one or more characters in a file name or a string:

  • *: any number of characters including none
  • ?: any single character
  • […]: any one of the characters inside the brackets

For example, let’s use ls to list all files that have a .txt extension:

$ ls *.txt
file.txt  notes.txt  report.txt

In this example, the pattern *.txt matches any file with a .txt extension.

We can also use ranges and character classes inside the brackets to specify a set of characters:

$ ls [[:alpha:]]*
file1  file3   file4  file6     File.txt    notes.txt   report.txt
file2  file34  file5  file.txt  notes.docx  Report.pdf

The pattern [[:alpha:]]* matches any file that starts with a letter, either uppercase or lowercase.

Unlike some regular expressions where * might need to be anchored, in globbing, * works independently of the position and can match any sequence of characters anywhere within the filename:

$ ls *port*
Report.pdf  report.txt

This command lists files containing the substring port anywhere in their names.

After understanding how to use globbing to match a pattern, let’s explore some methods we can use to exclude a pattern from a glob match.

3. Using Negation Operators

One way to exclude a pattern from a glob match is to use negation operators:

  • !: not operator
  • ^: caret operator

Typically, these operators mean not and they invert the meaning of patterns within brackets.

For instance, let’s list all the files that don’t have a .txt extension:

$ ls *.[!txt]
file1  file2  file3  file34  file4  file5  file6  Report.pdf

The ! operator inside the brackets matches anything except the characters in the bracket. The *.[txt] pattern matches all files with names that don’t end with .txt. Therefore, in this example, .[!txt] excludes all files in the current working directory that don’t have a .txt extension.

The ^ operator also functions in a similar way:

$ ls file[^?]
file1  file2  file3  file4  file5  file6

This command lists all the filenames that don’t have four characters and starts with file.

However, this method only works for simple cases and it may not work for complex patterns that involve multiple characters or wildcards. In this case, we can use extended globbing.

4. Using Extended Globbing

Extended globbing is a feature of Bash that enables us to use more complex patterns and operators to match multiple files or directories using wildcards:

  • ?(pattern-list): zero or one occurrence of the given patterns
  • *(pattern-list): zero or more occurrences of the given patterns
  • +(pattern-list): one or more occurrences of the given patterns
  • @(pattern-list): one of the given patterns
  • !(pattern-list): anything except one of the given patterns

Here, pattern-list is a list of items that are separated by the pipe symbol.

Notably, before we can use extended globbing, we must enable the feature by using the shopt command:

$ shopt -s extglob

This command has the -s option to set certain features. For example, the extglob option enables the use of the extended globbing feature.

Later, we can disable extglob to return to the default globbing behavior:

$ shopt -u extglob

The option -u which stands for unset was used to reset the globbing behavior to the default.

Now, let’s see an example of using extended globbing to exclude a pattern from a glob match:

$ shopt -s extglob
$ ls !(*.jpg|*.gif|*.png)
file1  file3   file4  file6     File.txt    notes.txt   report.txt
file2  file34  file5  file.txt  notes.docx  Report.pdf
$ shopt -u extglob

This lists all the files that don’t seem to be JPEGs, GIFs, or PNGs.

In general, the advantage of using extended globbing is that it can include or exclude more than one character or a sequence of characters from the glob match. However, extglob may not be available in all shells.

5. Using GLOBIGNORE

Another way to exclude a pattern from a glob match is to use the special GLOBIGNORE variable. This is a feature of Bash that enables us to specify a list of patterns that should be ignored by globbing.

Here’s an example of how we can use GLOBIGNORE:

$ GLOBIGNORE="*.jpg:*.gif:*.png"
$ ls
file1  file3   file4  file6     File.txt    notes.txt   report.txt
file2  file34  file5  file.txt  notes.docx  Report.pdf
$ unset GLOBIGNORE

In this example, the GLOBIGNORE variable is set to exclude files with .jpg.gif, and .png. When we then use ls, it implicitly lists all files except those matching the specified patterns.

It’s important to note that GLOBIGNORE isn’t supported in all shells. However, it’s commonly found in Bash and some other Bourne-like shells.

6. Conclusion

In this article, we’ve learned how to exclude a pattern from a glob match in the shell. In particular, we used different methods and techniques such as negation operators, extended globbing, and GLOBIGNORE. We’ve also seen some examples of using these features in Bash.