Search code examples
linuxbashshellglobextglob

How bash inverse pattern matching works internally in extglob?


Below files are present in current directory.

-rw-r--r-- 1 kazama kazama 0 Feb 16 08:50 london_july_2001_001.jpeg
-rw-r--r-- 1 kazama kazama 0 Feb 16 08:50 london_march_2004_002.png
-rw-r--r-- 1 kazama kazama 0 Feb 16 08:50 newyork_dec_2012_005.jpeg
-rw-r--r-- 1 kazama kazama 0 Feb 16 08:50 paris_sept_2007_003.jpg

I want to filter all images except which starts with "paris" text.

I have tried below command which works as per my expectation.

ls -l !(paris*)

But, I do not understand why below 2 commands do not give me expected output. In both of the cases it shows all the 4 files.

ls -l !(paris)*.*(jpeg|jpg|png)

ls -l !(paris)*

How bash interprets this extended globbing syntax internally ?Is it first trying to match !(paris) then it tries to match (jpeg|jpg|png) ?


Solution

  • !(paris) matches anything but paris, which includes paris_, pari, par, pa, p, and even the empty string. Bash will find something that doesn't match paris and try to match the rest of the pathname against the rest of the pattern. See:

    $ echo !(paris)london*
    london_july_2001_001.jpeg london_march_2004_002.png
    $ echo !(paris)_*
    london_july_2001_001.jpeg london_march_2004_002.png newyork_dec_2012_005.jpeg paris_sept_2007_003.jpg
    $ echo !(paris)_*_*_*
    london_july_2001_001.jpeg london_march_2004_002.png newyork_dec_2012_005.jpeg