11

How can I find every file and directory matching a pattern, excluding one directory using find?

Say I have the following file structure;

.
  foo-exclude-me/
    foo.txt
  foo-exclude-me-not/
    foo.txt
  bar/
    foo.txt
    foobar/
      bar.txt
      foofoo.txt

how would I get the following output using find:

./bar/foo.txt
./bar/foobar
./bar/foobar/foofoo.txt
./foo-exclude-me-not
./foo-exclude-me-not/foo.txt

I have tried using both of the following command:

find . -name 'foo-exclude-me' -prune -o -name 'foo*'
find . -name 'foo*' \! -path './foo-exclude-me/*'

but both of them return this:

./bar/foo.txt
./bar/foobar
./bar/foobar/foofoo.txt
./foo-exclude-me # << this should be excluded
./foo-exclude-me-not
./foo-exclude-me-not/foo.txt

How can I properly exclude the foo-exclude-me directory?

5
  • Try using foo-exclude-me instead of ./foo-exclude-me. Also try appending -print at the end of the command.
    – n0pe
    Mar 7, 2013 at 17:55
  • @MaxMackie perfect :)
    – Tyilo
    Mar 7, 2013 at 18:00
  • It fixed it? Which was the fix that worked for you? I can put it in an answer instead of a comment.
    – n0pe
    Mar 7, 2013 at 18:01
  • @MaxMackie using both -print and foo-exclude-me instead of ./foo-exclude-me.
    – Tyilo
    Mar 7, 2013 at 18:04
  • Awesome, looks like Gilles beat me to it though :)
    – n0pe
    Mar 7, 2013 at 18:13

2 Answers 2

11
find . -name 'foo-exclude-me' -prune -o -name 'foo*' -print

With no -print, the implicit default action applies to every match, even pruned ones. The explicit -print applies only under the specified conditions, which are -name 'foo*' only in the else branch of -name 'foo-exclude-me'.

Generally speaking, use an explicit -print whenever you're doing something more complex than a conjunction of predicates.

Your second attempt with ! -path './foo-exclude-me/*' didn't work because ./foo-exclude-me doesn't match ./foo-exclude-me/* (no trailing /). Adding ! -path ./foo-exclude-me would work.

0
-2

-bash-4.1$ find . -exec ls -l {} + -name 'a.out' -prune -o -name '*' -exec rm -f {} + -exec ls -l {} +

-rw-r--r--. 1 oradba dba  499 Jan 18 19:30 ./a.out
-rw-r--r--. 1 oradba dba  499 Jan 18 20:59 ./b.out
-rw-r--r--. 1 oradba dba  499 Jan 18 20:59 ./c.out
-rw-r--r--. 1 oradba dba  499 Jan 18 20:59 ./d.out

.:
total 16
-rw-r--r--. 1 oradba dba 499 Jan 18 19:30 a.out
-rw-r--r--. 1 oradba dba 499 Jan 18 20:59 b.out
-rw-r--r--. 1 oradba dba 499 Jan 18 20:59 c.out
-rw-r--r--. 1 oradba dba 499 Jan 18 20:59 d.out
rm: cannot remove `.': Is a directory
ls: cannot access ./b.out: No such file or directory
ls: cannot access ./d.out: No such file or directory
ls: cannot access ./c.out: No such file or directory
.:
total 4
-rw-r--r--. 1 oradba dba 499 Jan 18 19:30 a.out

3
  • Used the prune option to skip a.out and works fine - art.s
    – user211226
    Jan 19, 2017 at 1:07
  • You absolutely do not explain why -prune is relevant. -prune is one of the most convoluted options to find 'cause it disables -print (which is enabled by default)
    – grochmal
    Jan 19, 2017 at 1:54
  • -prune True; if the file is a directory, do not descend into it. - So it will not work itself into the directories as a protection. - art.s
    – user211226
    Jan 19, 2017 at 2:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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