46

I am using find -type f command to recursively find all files from a certain starting directory. However, I would like to have some directories prevented from entering and extracting names of files inside. So basically I am looking for something like:

find . -type f ! -name "avoid_this_directory_please"

Is there a functioning alternative to this?

Peter Mortensen
  • 1,029
  • 1
  • 8
  • 10
user219860
  • 461
  • 1
  • 4
  • 3
  • 10
    There's a [dozen questions](http://unix.stackexchange.com/search?q=find+%22-prune%22) on the troubles with using `-prune`: it can be a bit confusing. Also [this on stackoverflow](http://stackoverflow.com/a/1489405/6372809) describes why it's such an annoying thing to use. – ilkkachu Mar 08 '17 at 21:26
  • 2
    Even if this is a dupe the best answer here is clearer than the best answer on the "correct" question. – chicks Oct 09 '18 at 16:04
  • 2
    Hmm, "find -prune isn't working for me" sure sounds different from "how do I exclude directories from find output?" to me ... – SamB Oct 09 '19 at 19:34
  • @SamB Agreed, this can't possibly be a duplicate. – Hashim Aziz Oct 09 '19 at 22:41

4 Answers4

55

This is what the -prune option is for:

find . -type d -name 'avoid_this_directory_please' -prune -o \
    -type f -print

You may interpret the above as "if there's a directory called avoid_this_directory_please, don't enter it, otherwise, if it's a regular file, print its pathname."

You may also prune the directory given any other criteria, e.g. its full pathnames from the top-level search path:

find . -type d -path './some/dir/avoid_this_directory_please' -prune -o \
    -type f -print
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • 2
    i was going to write the same thing, slightly differently, as `find . \( -type d -name 'avoid_this_directory_please' -prune \) -o \( -type f -print \)`, but I like your syntax better. Thanks. – Tim Kennedy Mar 08 '17 at 21:20
  • 3
    @TimKennedy You would probably need the parens if you wanted to do `find . -type d \( -name "A" -o -name "B" \) -prune -o -type f -print`. – Kusalananda Mar 08 '17 at 21:22
  • good point. i don't even know when/where I learned to do it with the parentheses. that age is lost in the mists of time. :) – Tim Kennedy Mar 08 '17 at 21:23
  • 2
    This will of course prune off any directories called `avoid_this_directory_please` anywhere in the tree, not just top level ones. `-path` would allow for more control in that, as the [man page](https://linux.die.net/man/1/find) ([quoted below](http://unix.stackexchange.com/a/350092/170373) by Xen2050) states. – ilkkachu Mar 08 '17 at 21:30
  • I did not know that `-prune` considered everything after the first `find` argument, including `-type` and was puzzled at failing to prune directories with `find / -type f -path /proc -prune -o -name foo -print`. Seeing both `-type d` and `-type f` in the same command is what made it click for me. Now I finally feel confident in using `find`, thanks. – kelvin Apr 27 '20 at 02:18
14

To avoid a directory try the -path test:

find . -type f ! -path '*/avoid_this_directory_please/*'
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
Stephen Rauch
  • 4,209
  • 14
  • 22
  • 32
  • 9
    Note that while it will prevent files inside `avoid_this_directory_please` from being selected (unless their path contain invalid characters), it will not stop `find` from descending in there. That's why `-prune` is better here. – Stéphane Chazelas Mar 08 '17 at 21:22
  • This is sooooo much better than using `prune`. I always have to read for half an hour to figure out specifying what I don't want for find and then pair with OR logic to obtain the files I want. – Merlin Jul 29 '19 at 04:30
  • @Merlin It obviously depends on what you want to achieve. With `-prune`, `find` won't even look in the selected paths, while with `! -path`, it would still enter the path and examine everything. – Kusalananda Sep 04 '19 at 11:27
9

From man find, in the -path section, apparently combining the other 2 answers

To  ignore a whole directory tree, use -prune rather than
checking every file in the tree.  For example, to skip the directory
`src/emacs'  and  all  files and directories under it, and print the
names of the other files found, do something like this:

          find . -path ./src/emacs -prune -o -print
Xen2050
  • 2,211
  • 15
  • 15
7

Try this

find -name "*.js" -not -path "./directory/*"
  • This works if only you are looking for one extension type. The following will fail: `find -name "*.js" -o -name "*.css" -not -path "./directory/*"` – Subhamoy S. Dec 04 '17 at 10:28