Skip to content
Advertisement

How to limit a search of a directory with “find” command?

I am trying to make a Bash script that would create symlinks to directories that have a “target” subdirectory. I use “find” command to search for the “target” directories and put the filepaths to array.

array_of_dirs=( $(find -type d -name "target") )

The array is looped through and symbolic links are made to directories. My issue is that the depth of the directory structure is unknown and the subdirectories can have multiple “target” directories.

The directory structure could be:

    .
    ├── blaah
    │   ├── jee1
    │   │   └── omg1
    │   │       └── bar1
    │   │           └── target <--- When this is found, no need to continue into subdirectories
    │   │               └── wtf1
    │   │                   └── target
    │   ├── jee2
    │   │   └── target
    │   ├── jee3
    │   └── jee4
    └── blaah2
        ├── jou1
        │   └── target
        ├── jou2
        └── jou3
            └── target <--- When this is found, no need to continue into subdirectories
                ├── foo1
                │   └── target
                ├── foo2
                │   └── target
                └── foo3
                    └── target

At the moment these paths are found and there are unwanted symbolic links created.

    ./blaah/jee1/omg1/bar1
    ./blaah/jee1/omg1/bar1/target/wtf1 <--- Unwanted
    ./blaah/jee2
    ./blaah2/jou1
    ./blaah2/jou3
    ./blaah2/jou3/target/foo1 <--- Unwanted
    ./blaah2/jou3/target/foo2 <--- Unwanted
    ./blaah2/jou3/target/foo3 <--- Unwanted

How could I limit that when the “target” is found the search will not continue further into the subdirectories?

Advertisement

Answer

The shortest solution first, even if it was found at last (suggested by Eastman himself in a comment).

array_of_dirs=($(find -type d -name "foo" -prune))

With the -path option, you may exclude paths, containing the whole token “/target/”. In contrast to -name, which only evaluates the filename itself, the path needs globbing to catch foo/target and target/bar. And of course it needs negation -not -path “/target/“.

array_of_dirs=($(find -type d -not -path "*/target/*" -name "target"))

With a test on my system and foo instead of target:

find -type d -name "foo" 
./tmp/bar/bar/foo
./tmp/bar/foo
./tmp/test/bar/foo
./tmp/foo
./tmp/foo/foo
./tmp/foo/foo/foo

find -type d -not -path "*/foo/*" -name "foo" 
./tmp/bar/bar/foo
./tmp/bar/foo
./tmp/test/bar/foo
./tmp/foo

The option -path … -prune seems to have the same effect. For detailed differences, please study the manual carefully. A short test revealed a 10% time benefit by using prune, but it can be a caching effect or random influence.

(needlessly verbose intermediate solution:)

find -type d -name “foo” -path “/foo” -prune

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement