For example, I have files named

A_1.txt A_t_1.txt A_ts_1.txt A_tsa_1.txt

in a directory ~/admin/packages/.

I am building a for loop to by globbing to A_1.txt

for f in ~/admin/packages/*_1.txt

It's obvious that this can potentially glob to any one of these files.

Specifically I would like to use an "exception" command (if it exists) to say glob to any file as long as it does not have a t, s, a before _1.txt.

EDIT: I forgot to mention that I have the path stored as a variable.


for f in ${PROJECT}...

You can do this using the following extglob pattern in bash:


Enable extglob at first (if not enabled) by:

shopt -s extglob

Then you can do:

for f in ~/admin/packages/!(*t|*s|*a)_1.txt; do ##Something; done


$ echo *_1.txt
A_1.txt Ab_1.txt A_t_1.txt A_ts_1.txt A_tsa_1.txt

$ shopt -s extglob

$ echo !(*t|*s|*a)_1.txt
A_1.txt Ab_1.txt

Shortened (thanks to chaos):


You could set your PROJECT var to ~/admin/packages/*[^tsa]_1.txt


If you can modify it.


Use a case statement to weed out the exceptions, like this:

for f in ${PROJECT}; do
    case "$f" in *[tsa]_1*) continue;; esac

    # ... actual work here ...

(in bash) The exact answer to your request is to use GLOBIGNORE:

By executing this command:

LESS=+/'^ *GLOBIGNORE' man bash


A colon-separated list of patterns defining the set of filenames to be ignored by pathname expansion. If a filename matched by a pathname expansion pattern also matches one of the patterns in GLOBIGNORE, it is removed from the list of matches.

So, by setting GLOBIGNORE like this:

$  ls *
A_1.txt  A_t_1.txt  A_ts_1.txt  A_tsa_1.txt
$ GLOBIGNORE=*t_1.txt:*s_1.txt:*a_1.txt
$ ls *

After that you may restore GLOBIGNORE to empty with unset GLOBIGNORE.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.