On Linux, iterating through a large list of files manually may be error-prone and not very efficient. Instead, you can leverage the Bash wildcards which allows you to define patterns to match against filenames or strings. This process is known as globbing.
The Bash Wildcards are characters with special meanings when used for Pattern Matching. Matching patterns are also called glob patterns. You can use glob patterns for filenames matching but also as part of a Bash If statement where a double bracket condition can perform pattern matching against a string.
It is very common to use the Bash Brace Expansion in addition to the Bash Wildcards, though they are two separate Bash features.
What is a Bash Wildcard?
Bash Wildcards is the unofficial term for the Bash Pattern Matching characters. Pattern Matching notation is similar to regular expression notation with some slight differences. Pattern Matching is defined as part of the POSIX standard.
In computer programming, wildcards are the special characters used as part of glob patterns. The wildcard terminology is not found in the Bash manual or the POSIX standard but is often implied and used by practitioners.
The Bash Brace Expansion uses the curly braces {...}
which are not part of the wildcards. Pattern Matching and Brace Expansion are two different Bash shell features, though they are often used together.
The wildcards, or Pattern Matching characters, are *
, ?
, and [...]
characters and have specific meanings to simplify long and complex command lines.
What are the Wildcards (Pattern Matching) characters?
Wildcards | Description |
---|---|
? | A question-mark is a pattern that matches any single character. |
* | An asterisk is a pattern that matches any number of any characters, including the null string/none. |
[...] | The square brackets matches any one of the enclosed characters. |
The Match All Wildcard *
Certainly, the most widely used wildcard is the asterisk *
. It will match any strings, including the null string.
Note that in Bash when the globstar
option is enabled, two adjacent asterisk *
used as a single pattern will match all files and zero or more directories and subdirectories. If followed by a slash /
, it will match only directories and subdirectories.
The examples below use a filename expansion in Bash using Pattern Matching and assign the result to a Bash Array.
[me@linux ~]$ ls tmp/file*
tmp/file1 tmp/file2
[me@linux ~]$ shopt -s globstar
[me@linux ~]$ list=(tmp/); echo ${list[@]}
tmp/
[me@linux ~]$ list=(tmp/**); echo ${list[@]}
tmp/ tmp/file1 tmp/file2 tmp/tmp2 tmp/tmp2/afile
[me@linux ~]$ list=(tmp/**/); echo ${list[@]}
tmp/ tmp/tmp2/
[me@linux ~]$ list=(tmp/**/*); echo ${list[@]}
tmp/file1 tmp/file2 tmp/tmp2 tmp/tmp2/afile
The Match One Wildcard ?
The question mark ?
match for any single character.
[me@linux ~]$ ls
pic1.jpg pic1.txt pic2.jpg pic3.jpg pic4.jpg pic5.jpg pic-big.jpg pic.jpg pic-small.jpg pic.txt pic1.txt pic2.txt pic1.bmp
[me@linux ~]$ ls pic?.jpg
pic1.jpg pic2.jpg pic3.jpg pic4.jpg pic5.jpg
The Match Range Wildcard [...]
The square brackets [...]
, known as the RE Bracket Expression, let you match any one of the enclosed characters. You can define a range expression by separating characters with a hyphen -
. You can also, negate an expression using the exclamation point !
, or the caret symbol ^
in Bash. To match the hyphen -
or closing square bracket ]
, you will need to include those characters as the first or last character of the pattern matching.
Wildcard | Description | Example | Matches | Does Not Match |
---|---|---|---|---|
[!a] | Match one character which is not n | B[!a]ll | Bell | Ball |
[!a-z] | Match one character that is not in the range a-z | File-[!a-z].png | File-1.png, File-2.png, etc. | File-a.png, File-b.png, etc |
Enabling the extglob
shell option in bash would allow for extended pattern matching and allow more advanced pattern operators which makes it closer to regular-expression notations. The extended regular expressions are often used in a
Bash If Statement with the =~
conditional operator.
Wildcards | Description |
---|---|
?(pattern-list) | Matches zero or one occurrence of the given patterns. |
*(pattern-list) | Matches zero or more occurrences of the given patterns. |
+(pattern-list) | Matches one or more occurrences of the given patterns. |
@(pattern-list) | Matches one of the given patterns. |
!(pattern-list) | Matches anything except one of the given patterns. |
Additionally, you can specify a class of characters with the syntax [:class:]
where the class is defined by the
LC_TYPE POSIX standard variable as detailed in the table below.
[:alnum:] | Alphanumeric characters, meaning any alpha + digit . |
[:alpha:] | Any uppercase or lowercase letters. |
[:ascii:] | Any of the 128 ASCII characters. It is a bash specific character class. |
[:blank:] | Only space and tab characters. |
[:cntrl:] | Non-printable characters, i.e. control characters. |
[:digit:] | Numbers in decimal, 0 to 9. |
[:graph:] | Graphically printable characters, excluding space. |
[:lower:] | Lowercase letters. |
[:print:] | Printable characters, including space. |
[:punct:] | Punctuation characters. |
[:space:] | Any white-spaced character, including tabs, newline, carriage-return, and similar. |
[:upper:] | Uppercase letters. |
[:word:] | Alphanumeric characters with underscore character _ , meaning alnum + _ . It is a bash specific character class. |
[:xdigit:] | Hexadecimal digits. |
Below are some more complex examples using extended glob patterns and character class.
[me@linux ~]$ shopt -s extglob
[me@linux ~]$ list=(tmp/*([[:alpha:]])[0-9]); echo ${list[@]}
tmp/file1 tmp/file2 tmp/tmp2
[me@linux ~]$ list=(tmp/+([[:word:]])); echo ${list[@]}
tmp/file1 tmp/file2 tmp/tmp2
What is the Bash Brace Expansion and the Curly Brackets Wildcard {}
?
Remember that the Brace Expansion {..}
are simply doing text substitution before any other bash expansion. It is not part of the Pattern Matching, or globbing, feature in bash. I reference this here as it is often used in conjunction with globbing.
# Range character with Bash Wildcards
[me@linux ~]$ ls pic[1-3].jpg
pic1.jpg pic2.jpg pic3.jpg
# List of values with Brace Expansion
[me@linux ~]$ ls pic1.{txt,jpg,bmp}
pic1.txt pic1.jpg pic1.bmp
You can use wildcards and brace expansion together.
[me@linux ~]$ ls pic[1-3].{txt,jpg}
pic1.jpg pic1.txt pic2.jpg pic3.jpg
We have seen how to perform our ls
search but you can also use those bash wildcards with any of your Bash commands.
# Example 1
[me@linux ~]$ ls
a_too_short_file_name_with_lot_of_ch4r4ct3r3.txt
[me@linux ~]$ mv a_too_{short,long}_file_name_with_lot_of_ch4r4ct3r3.txt
[me@linux ~]$ ls
a_too_long_file_name_with_lot_of_ch4r4ct3r3.txt
# Example 2
[me@linux ~]$ ls
dest pic1.jpg pic2.jpg pic3.jpg
[me@linux ~]$ cp pic[1-3].jpg dest
[me@linux ~]$ ls dest/
pic1.jpg pic2.jpg pic3.jpg
👉 Read more about Braces Expansion in the post Printing a Sequence of Letters or Numbers
Detailed Examples & FAQ
How to copy the files from the current directory to a subdirectory using globbing?
By using the
extended globbing option you can easily list all current files with an extended pattern like !(subdir)
and use the cp
command to copy the files. You can also use the dotglob
shell option if you want to include files and directories that start with a dot.
[me@linux ~]$ ls
file1 file2 tmp2
[me@linux ~]$ shopt -s extglob
[me@linux ~]$ ls !(tmp2)
file1 file2
[me@linux ~]$ cp -r !(tmp2) tmp2
[me@linux ~]$ ls tmp2/
file1 file2