user3581955
user3581955

Reputation: 77

BASH: excluding a directory in "find" command

I'd like to use find command with excluding a directory.

I have this:

GLUE="$GLUE -not -iwholename */dir3/*"

And I want to use a GLUE variable in a find command (find $GLUE [...]). Unfortunately, instead of -not -iwholename */dir3/* in GLUE I get -not -iwholename dir3/file1 dir3/file2 dir3/file3, i.e., */dir3/* turns into names of files which meet this condition. And, of course, find doesn't work because of it. How to stop that?

Upvotes: 2

Views: 190

Answers (2)

gniourf_gniourf
gniourf_gniourf

Reputation: 46813

Let me answer this question first:

How can I use find to search recursively while excluding a directory from the search? My find command supports the -prune action and the common extensions (e.g., provided by GNU find).

You're very lucky that your find supports the -prune action. Congratulations!

In this case, only add:

\! \( -name 'dir_to_exclude' -prune \)

This will be false if the current name processed by find is dir_to_exclude, and at the same time prune (i.e., cut that branch) from the search tree1.

Let's try it (in a scratch directory):

$ mkdir {a,b,c,d}/{,1,2,3}
$ touch {a,b,c,d}/{,1,2,3}/{file1,file2}
$ tree
.
|-- a
|   |-- 1
|   |   |-- file1
|   |   `-- file2
|   |-- 2
|   |   |-- file1
|   |   `-- file2
|   |-- file1
|   `-- file2
|-- b
|   |-- 1
|   |   |-- file1
|   |   `-- file2
|   |-- 2
|   |   |-- file1
|   |   `-- file2
|   |-- file1
|   `-- file2
`-- c
    |-- 1
    |   |-- file1
    |   `-- file2
    |-- 2
    |   |-- file1
    |   `-- file2
    |-- file1
    `-- file2

9 directories, 18 files
$ find \! \( -name a -prune \)
.
./b
./b/file2
./b/1
./b/1/file2
./b/1/file1
./b/file1
./b/2
./b/2/file2
./b/2/file1
./c
./c/file2
./c/1
./c/1/file2
./c/1/file1
./c/file1
./c/2
./c/2/file2
./c/2/file1

Looks good!


Now, you shouldn't put your arguments to find (or, more generally your commands and arguments) in a variable, but in an array! If you don't you'll very soon run into problems with arguments containing spaces or, like in your OP, wildcards.

Put your glue stuff in an array: for example, to find all the files that have a 1 in their name and are empty2:

glue=( '-name' '*1*' '-type' 'f' '-empty' )

Then an array of the exclude this directory:

exclude_dir=( '!' '(' '-name' 'a' '-prune' ')' )

Then find all files that have a 1 in their name and are empty, while excluding directory a (in the same scratch directory as before):

$ find "${exclude_dir[@]}" "${glue[@]}"
./b/1/file1
./b/file1
./b/2/file1
./c/1/file1
./c/file1
./c/2/file1

Looks really good! (and observe the quotes!).


1 If you really want to be sure that you're only excluding the directory with name dir_to_exclude, in case you have a file called dir_to_exclude, you can specify it thus:

\! \( -name 'dir_to_exclude' -type d -prune \)

2 I'm using a lot of quotes here. Just a good habit that actually saves me for the wildcard part *1* and for the parentheses too!

Upvotes: 2

PradyJord
PradyJord

Reputation: 2160

find ./ -iname ! -iname <dirname of file name to be not part of search results>

find ./ -iname <file name> ! -path "./dirt o be Excluded/*" 

I hope one will help

Upvotes: 2

Related Questions