Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop recursion of find command if match found

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]
like image 779
Eric Lilja Avatar asked Dec 23 '22 01:12

Eric Lilja


1 Answers

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
like image 178
gniourf_gniourf Avatar answered Jan 09 '23 17:01

gniourf_gniourf