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.
    – nopcorn
    Commented Mar 7, 2013 at 17:55
  • @MaxMackie perfect :)
    – Tyilo
    Commented 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.
    – nopcorn
    Commented Mar 7, 2013 at 18:01
  • @MaxMackie using both -print and foo-exclude-me instead of ./foo-exclude-me.
    – Tyilo
    Commented Mar 7, 2013 at 18:04
  • Awesome, looks like Gilles beat me to it though :)
    – nopcorn
    Commented 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
    Commented 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
    Commented 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
    Commented Jan 19, 2017 at 2:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .