Bash extended glob – match files without prefix

bashbash-expansionwildcards

I'm trying to match filenames for a fail2ban jail – so I need to use filename globbing only – not regexes or bash scripting.

My /var/log/apache2 directory contains files including:

example.com.error.log
db.example.com.error.log
app1.example.com.error.log
app2.example.com.error.log

I'm trying to create a glob to match all files ending in .error.log except db.example.error.log – is this possible?

I've tried !(db)*.error.log but this still matches db.example.com.error.log. I'm guessing the !() is matching no characters, allowing the * to match from the beginning of the filename.

Note: I don't want to have to extend the glob when new appX logfiles are added, so I can't use @() with the list of currently-known non-db filenames.

(Background: I want to create a filter banning anyone requesting any phpMyAdmin URLs on any domain except db.example.com)

Best Answer

The extended filename globbing pattern (supported by bash with the extglob shell option activated, and also by ksh93)

!(db*).error.log

will ignore anything that starts with db.

To be more specific:

!(db.example.com).error.log

This will ignore any name in the current directory that starts with exactly db.example.com.

The !(db.example.com) pattern acts like a "special *" that will not match the the string db.example.com.


Your pattern,

!(db)*.error.log

excludes any name that starts with db, but allows any string after that, which obviously includes db.

By the same analogy as above, !(db) acts "like *" but won't match the exact string db, leaving us with the pattern **.error.log so to speak (with the first * being "special").