Using GNU findutils, I need to search a directory tree for a certain file. If the file has been found for a given branch, I want to prevent find from recursing further into the branch. Say I want to find the file foo, and this is my directory tree:
├── a
│ ├── a1
│ │ └── foo
│ └── foo
├── b
└── c
└── foo
Given I am searching the tree above, I want to find a/foo and c/foo. However, I don't want to find a/a1/foo since I already found foo in a parent directory to a1. It seems I should use the -prune flag to the find command and I found this link https://unix.stackexchange.com/questions/24557/how-do-i-stop-a-find-from-descending-into-found-directories, for example, but I cannot make it work. My attempts include:
$ find -name foo -type f -prune
./a/a1/foo <- Unwanted hit
./a/foo
./c/foo
and
$ find -name foo -type f -prune -exec find ../foo -type f {} \;
find: paths must precede expression: ./a/a1/foo
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
find: paths must precede expression: ./a/foo
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
find: paths must precede expression: ./c/foo
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
This will print the directories that contain foo
, and will not recurse in their subdirectories:
find -type d -exec test -f {}/foo \; -print -prune
The behavior for {}/foo
is explicitly left undefined by POSIX:
If a utility_name or argument string contains the two characters "{}", but not just the two characters "{}", it is implementation-defined whether find replaces those two characters or uses the string without change.
but works as expected with GNU find
(and you tagged the question with gnu-findutils). As Kamil Cuk rightly suggests in the comments, if you're using non-GNU find
or if you want a more portable solution, use:
find -type d -exec sh -c 'test -f "$1"/foo' -- {} \; -print -prune