ryeballar ryeballar - 6 months ago 17
Bash Question

Shell globbing exclude directory patterns

Disregarding commands that can be used in association with shell globs, I would like to accomplish excluding specific directory patterns across all directories and sub-directories from a glob pattern.

Let's say I have this directory structure:

+-- a
+-- a1
+-- assets
+-- a1-1
+-- a1-1.js
+-- a1-2
+-- a1-2.js
+-- a2
+-- a2.js
+-- b
+-- b1
+-- b1-2
+-- b1-2-3
+-- assets
+-- b1-2-3.js
+-- b.js
+-- c
+-- c.js


I would like to list all js files that do not have
assets
in their file paths.

What I've tried so far:

$ shopt -s globstar extglob
$ ls ./**/!(assets)/**/*.js


Not only did the pattern above achieve it's goal, it even shows duplicate outputs. I am aware that I can do something like this:

$ ls ./**/*.js | grep -v "assets"


Or any other commands that can be piped, I simply want a pure shell glob pattern.

Expected Output:

a/a2/a2.js
b/b.js
c/c.js

Answer

Michael's answer is right. ** matches too much (greedy match), including assets.

So, with this tree:

.
|-- a
|   |-- a1
|   |   +-- assets
|   |       |-- a1-1
|   |       |   +-- a1-1.js
|   |       +-- a1-2
|   |           +-- a1-2.js
|   +-- a2
|       +-- a2.js
|-- assets
|   +-- xyz.js
|-- b
|   |-- b1
|   |   +-- b1-2
|   |       +-- b1-2-3
|   |           +-- assets
|   |               +-- b1-2-3.js
|   +-- b.js
+-- c
    +-- c.js

The .js files are:

$ find . -name '*.js'
./assets/xyz.js
./a/a2/a2.js
./a/a1/assets/a1-2/a1-2.js
./a/a1/assets/a1-1/a1-1.js
./c/c.js
./b/b.js
./b/b1/b1-2/b1-2-3/assets/b1-2-3.js

Below pattern should work. Note that it has 2 patterns separated by space.

$ ls -1 ./!(**/assets)/!(assets/**)/*.js ./!(assets)/*.js 
./a/a2/a2.js
./b/b.js
./c/c.js
Comments