Bash: Pattern matching

In their simplest form, globs are wildcards. That is, * matches zero or more characters.

$ touch {a,b,c}.txt {x,y,z}.md
$ ls *.txt
a.txt  b.txt  c.txt

If the globstar shell option is enabled, globs can recursively match the contents of subdirectories in a filename expansion context.

$ shopt -s globstar
$ mkdir -p a/b/c/
$ touch a/a.txt a/b/b.txt a/b/c/c.txt
$ ls **/*.txt
a/a.txt  a/b/b.txt  a/b/c/c.txt

You may also use ? to match single characters

$ touch a.txt .a.txt.swp .a.txt.swo the.swarm.mp4
$ shopt -s dotglob
$ ls *.sw*
.a.txt.swo  .a.txt.swp  the.swarm.mp4
$ ls *.sw?
.a.txt.swo  .a.txt.swp

Yes, it's a strained example.

There are also character range expressions that look like [a-z0-9] or similar. Note that they're highly locale dependent, so it may be a good idea to enable the globasciiranges shell option to force the use of the C locale. Similar to regular expressions, you can negate range expressions with a ! or a ^ as the first character inside the square brackets.

$ touch {a,b,c,d,e,f,g,h,i}.txt
$ ls [^a-f]*.txt
g.txt  h.txt  i.txt
$ ls [[:xdigit:]].txt
a.txt  b.txt  c.txt  d.txt  e.txt  f.txt
$ ls [:xdigit:].txt
d.txt  g.txt  i.txt

Pay attention to the last example. The character classes must be inside double square brackets.

You may set the GLOBIGNORE environment variable to a colon-separated list of glob patterns to ignore.

$ touch {a,b,c,d}.txt
$ GLOBIGNORE="d.txt" ls *.txt
a.txt  b.txt  c.txt  d.txt
$ GLOBIGNORE="d.txt"
$ ls *.txt
a.txt  b.txt  c.txt
$ unset GLOBIGNORE

It appears as though you must set the variable before invoking a command. I think this is because the glob is expanded first, and then ls is execve(2)'d with the expanded arguments, at which time the GLOBIGNORE variable is evaluated.

You could also do ( GLOBIGNORE="d.txt"; ls *.txt ) so that you don't have to remember to unset GLOBIGNORE afterwards.

Because GLOBIGNORE must be set before the glob is evaluated, you may prefer to extended pattern matching by enabling the extglob shell option.

$ touch {a,b,c,d}.txt
$ shopt -s extglob
$ ls !(d).txt
a.txt  b.txt  c.txt

The extglob option enables the following extended pattern matching operators.

$ touch {a,b,c,d}.txt {aa,bb,cc,dd}.md
$ ls *.!(md)
a.txt  b.txt  c.txt  d.txt
$ ls @(a|b).*
a.txt  b.txt
$ ls +(a|b).*
aa.md  a.txt  bb.md  b.txt

There are several other glob-related shell options: