My directory looks like this:

$ ls
total 0
-rw-r--r-- 1 user user 0 Jun 18 22:44 file0
-rw-r--r-- 1 user user 0 Jun 18 22:44 file1
-rw-r--r-- 1 user user 0 Jun 18 22:44 file2
-rw-r--r-- 1 user user 0 Jun 18 22:44 file3
-rw-r--r-- 1 user user 0 Jun 18 22:44 file4
-rw-r--r-- 1 user user 0 Jun 18 22:44 file5
-rw-r--r-- 1 user user 0 Jun 18 22:44 file6
-rw-r--r-- 1 user user 0 Jun 18 22:44 file7
-rw-r--r-- 1 user user 0 Jun 18 22:44 file8
-rw-r--r-- 1 user user 0 Jun 18 22:44 file9

Using bash globbing, I want to match file2 to file6, excluding file3.

Since I could not find an and operator for matching multiple patterns, I figured I just use DeMorgan's law that a AND b is equivalent to !(!a OR !b) and write


which works as expected:

$ echo !(!(file[2-6])|file3)
file2 file4 file5 file6

Is there an easier, more direct way to achieve this?

  • 1
    Does the real life issue on your system also include removing a single name from a set of matching names in a short numerical range, like in your question, or is the actual situation more complex?
    – Kusalananda
    Commented Jun 19, 2022 at 11:28
  • 1
    @Kusalananda I am looking for a solution that works for the abstract problem of matching everything that matches pattern1 but not pattern2.
    – rewire
    Commented Jun 19, 2022 at 14:37
  • 1
    That makes your example rather deceptive as it's easy to leave out 4 from file[23456]. You may want to update your question with a further explanation of the general issue so that people here don't think you're interested in the specific example you are showing (which is now the case).
    – Kusalananda
    Commented Jun 19, 2022 at 14:44

2 Answers 2


You can apply two ranges [24-6], where 2 is the first and 4-6 is the second:

$ ls file[24-6]
file2 file4 file5 file6

Another example:

$ ls file[2356]
file2 file3 file5 file6



There is one special convention: two characters separated by '-' denote a range. (Thus, "[A-Fa-f0-9]" is equivalent to "[ABCDEFabcdef0123456789]".) One may include '-' in its literal meaning by making it the first or last character between the brackets. (Thus, "[]-]" matches just the two characters ']' and '-', and "[--0]" matches the three characters '-', '.', '0', since '/' cannot be matched.)


negate range :

printf '%s\n' file[!013789]

As stated here :

If the first character following the ‘[’ is a ‘!’ or a ‘^’ then any character not enclosed is matched.

setting GLOBIGNORE to the file you want to skip:

printf '%s\n' file*

see this :

The GLOBIGNORE shell variable may be used to restrict the set of file names matching a pattern. If GLOBIGNORE is set, each matching file name that also matches one of the patterns in GLOBIGNORE is removed from the list of matches.

Using extended globbing:

shopt -s extglob
printf '%s\n' file!([013789])

see extended globbing

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .