32

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?

| improve this question | | | | |
  • 7
    There's a dozen questions on the troubles with using -prune: it can be a bit confusing. Also this on stackoverflow describes why it's such an annoying thing to use. – ilkkachu Mar 8 '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 9 '18 at 16:04
  • 1
    Hmm, "find -prune isn't working for me" sure sounds different from "how do I exclude directories from find output?" to me ... – SamB Oct 9 '19 at 19:34
  • @SamB Agreed, this can't possibly be a duplicate. – Hashim Oct 9 '19 at 22:41
38

This is what the -prune option is for:

find . -type d -name "avoid_this_directory_please" -prune -o -type f -print

This basically says "if there's a directory called avoid_this_directory_please, don't enter it, otherwise, if it's a regular file, print its pathname".

| improve this answer | | | | |
  • 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 8 '17 at 21:20
  • 2
    @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 8 '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 8 '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 (quoted below by Xen2050) states. – ilkkachu Mar 8 '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 at 2:18
11

To avoid a directory try the -path test:

find . -type f ! -path '*/avoid_this_directory_please/*'
| improve this answer | | | | |
  • 5
    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 8 '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 4: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 4 '19 at 11:27
7

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
| improve this answer | | | | |
5

Try this

find -name "*.js" -not -path "./directory/*"
| improve this answer | | | | |
  • 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 4 '17 at 10:28

Not the answer you're looking for? Browse other questions tagged or ask your own question.