8

If the file structure is like this:

/a/p/c/d...
/c/a/c/g/f/...
/a/c/d/e/...
...

And I want to do this:

find -mindepth 3 -type d -name p -prune -or -name c -print

However, this command will not prune the 'p' directory and the first line will included. I know it's actually not a conflict. But how to prune 'p' with the mindepth applied?

1
  • I take it that d and e are files, not directories?
    – Anthon
    Commented Jun 3, 2013 at 6:57

3 Answers 3

4

With both FreeBSD and GNU find (which are some of the few implementations that support -mindepth), your -prune would only prune the p directories that are at depth 3 or deeper. Both the FreeBSD and GNU find documentation make it quite clear (here GNU documentation):

-- Option: -mindepth levels
    Do not apply any tests or actions at levels less than LEVELS (a
    non-negative integer).  `-mindepth 1' means process all files
    except the command line arguments.

You could always do it the standard way instead:

find . -type d -name p -prune -o -path './*/*/*' -name c -print

(-mindepth and -or are not standard find predicates, omitting the directory(s) is not standard either).

Or with zsh:

setopt extendedglob
printf '%s\n' ^p/^p/(^p/)#c
3
  • Just curious, why do you say this way is the "standard" way? Because you used -o instead of -or?
    – slm
    Commented Jun 3, 2013 at 7:17
  • @slm, the last sentence should make it clear. Commented Jun 3, 2013 at 7:19
  • I see the note in the man page now, it says -or is the same as -o but not POSIX compliance.
    – slm
    Commented Jun 3, 2013 at 7:23
1

I think I would do it this way:

find -mindepth 3 -type d ! -path '*/p/*' -name c -print

Based on @StephaneChazelas' feedback I believe this method would eliminate the extraneous searching into any /p/ directories:

find -mindepth 3 -type d -path '*/p/*' -prune -o -name c -print

Analyzing a find

To compare find commands you can add the debug switch -D search so that you can see how a particular find would perform vs. another.

I ran @StephaneChazelas' command vs. mine to see where the differences were. The 2 commands are run and their output is run into an sdiff below:

$ sdiff \
<(find -D search -mindepth 3 -type d -path '*/p/*' -prune -o -name c -print 2>&1) \
<(find -D search -type d -name p -prune -o -path './*/*/*' -name c -print 2>&1)
consider_visiting (early): `.': fts_info=FTS_D , fts_level= 0   consider_visiting (early): `.': fts_info=FTS_D , fts_level= 0
consider_visiting (late): `.': fts_info=FTS_D , isdir=1 ignor | consider_visiting (late): `.': fts_info=FTS_D , isdir=1 ignor
consider_visiting (early): `./a': fts_info=FTS_D , fts_level=   consider_visiting (early): `./a': fts_info=FTS_D , fts_level=
consider_visiting (late): `./a': fts_info=FTS_D , isdir=1 ign | consider_visiting (late): `./a': fts_info=FTS_D , isdir=1 ign
consider_visiting (early): `./a/c': fts_info=FTS_D , fts_leve   consider_visiting (early): `./a/c': fts_info=FTS_D , fts_leve
consider_visiting (late): `./a/c': fts_info=FTS_D , isdir=1 i | consider_visiting (late): `./a/c': fts_info=FTS_D , isdir=1 i
consider_visiting (early): `./a/c/d': fts_info=FTS_D , fts_le   consider_visiting (early): `./a/c/d': fts_info=FTS_D , fts_le
consider_visiting (late): `./a/c/d': fts_info=FTS_D , isdir=1   consider_visiting (late): `./a/c/d': fts_info=FTS_D , isdir=1
consider_visiting (early): `./a/c/d/e': fts_info=FTS_D , fts_   consider_visiting (early): `./a/c/d/e': fts_info=FTS_D , fts_
consider_visiting (late): `./a/c/d/e': fts_info=FTS_D , isdir   consider_visiting (late): `./a/c/d/e': fts_info=FTS_D , isdir
consider_visiting (early): `./a/c/d/e': fts_info=FTS_DP, fts_   consider_visiting (early): `./a/c/d/e': fts_info=FTS_DP, fts_
consider_visiting (late): `./a/c/d/e': fts_info=FTS_DP, isdir   consider_visiting (late): `./a/c/d/e': fts_info=FTS_DP, isdir
consider_visiting (early): `./a/c/d': fts_info=FTS_DP, fts_le   consider_visiting (early): `./a/c/d': fts_info=FTS_DP, fts_le
consider_visiting (late): `./a/c/d': fts_info=FTS_DP, isdir=1   consider_visiting (late): `./a/c/d': fts_info=FTS_DP, isdir=1
consider_visiting (early): `./a/c': fts_info=FTS_DP, fts_leve   consider_visiting (early): `./a/c': fts_info=FTS_DP, fts_leve
consider_visiting (late): `./a/c': fts_info=FTS_DP, isdir=1 i   consider_visiting (late): `./a/c': fts_info=FTS_DP, isdir=1 i
consider_visiting (early): `./a/p': fts_info=FTS_D , fts_leve   consider_visiting (early): `./a/p': fts_info=FTS_D , fts_leve
consider_visiting (late): `./a/p': fts_info=FTS_D , isdir=1 i | consider_visiting (late): `./a/p': fts_info=FTS_D , isdir=1 i
consider_visiting (early): `./a/p/c': fts_info=FTS_D , fts_le | consider_visiting (early): `./a/p': fts_info=FTS_DP, fts_leve
consider_visiting (late): `./a/p/c': fts_info=FTS_D , isdir=1 <
consider_visiting (early): `./a/p/c': fts_info=FTS_DP, fts_le <
consider_visiting (late): `./a/p/c': fts_info=FTS_DP, isdir=1 <
consider_visiting (early): `./a/p': fts_info=FTS_DP, fts_leve <
consider_visiting (late): `./a/p': fts_info=FTS_DP, isdir=1 i   consider_visiting (late): `./a/p': fts_info=FTS_DP, isdir=1 i
consider_visiting (early): `./a': fts_info=FTS_DP, fts_level=   consider_visiting (early): `./a': fts_info=FTS_DP, fts_level=
consider_visiting (late): `./a': fts_info=FTS_DP, isdir=1 ign   consider_visiting (late): `./a': fts_info=FTS_DP, isdir=1 ign
consider_visiting (early): `./c': fts_info=FTS_D , fts_level=   consider_visiting (early): `./c': fts_info=FTS_D , fts_level=
consider_visiting (late): `./c': fts_info=FTS_D , isdir=1 ign | consider_visiting (late): `./c': fts_info=FTS_D , isdir=1 ign
consider_visiting (early): `./c/a': fts_info=FTS_D , fts_leve   consider_visiting (early): `./c/a': fts_info=FTS_D , fts_leve
consider_visiting (late): `./c/a': fts_info=FTS_D , isdir=1 i | consider_visiting (late): `./c/a': fts_info=FTS_D , isdir=1 i
consider_visiting (early): `./c/a/c': fts_info=FTS_D , fts_le   consider_visiting (early): `./c/a/c': fts_info=FTS_D , fts_le
consider_visiting (late): `./c/a/c': fts_info=FTS_D , isdir=1   consider_visiting (late): `./c/a/c': fts_info=FTS_D , isdir=1
consider_visiting (early): `./c/a/c/g': fts_info=FTS_D , fts_   consider_visiting (early): `./c/a/c/g': fts_info=FTS_D , fts_
consider_visiting (late): `./c/a/c/g': fts_info=FTS_D , isdir   consider_visiting (late): `./c/a/c/g': fts_info=FTS_D , isdir
consider_visiting (early): `./c/a/c/g/f': fts_info=FTS_D , ft   consider_visiting (early): `./c/a/c/g/f': fts_info=FTS_D , ft
consider_visiting (late): `./c/a/c/g/f': fts_info=FTS_D , isd   consider_visiting (late): `./c/a/c/g/f': fts_info=FTS_D , isd
consider_visiting (early): `./c/a/c/g/f': fts_info=FTS_DP, ft   consider_visiting (early): `./c/a/c/g/f': fts_info=FTS_DP, ft
consider_visiting (late): `./c/a/c/g/f': fts_info=FTS_DP, isd   consider_visiting (late): `./c/a/c/g/f': fts_info=FTS_DP, isd
consider_visiting (early): `./c/a/c/g': fts_info=FTS_DP, fts_   consider_visiting (early): `./c/a/c/g': fts_info=FTS_DP, fts_
consider_visiting (late): `./c/a/c/g': fts_info=FTS_DP, isdir   consider_visiting (late): `./c/a/c/g': fts_info=FTS_DP, isdir
consider_visiting (early): `./c/a/c': fts_info=FTS_DP, fts_le   consider_visiting (early): `./c/a/c': fts_info=FTS_DP, fts_le
consider_visiting (late): `./c/a/c': fts_info=FTS_DP, isdir=1   consider_visiting (late): `./c/a/c': fts_info=FTS_DP, isdir=1
consider_visiting (early): `./c/a': fts_info=FTS_DP, fts_leve   consider_visiting (early): `./c/a': fts_info=FTS_DP, fts_leve
consider_visiting (late): `./c/a': fts_info=FTS_DP, isdir=1 i   consider_visiting (late): `./c/a': fts_info=FTS_DP, isdir=1 i
consider_visiting (early): `./c': fts_info=FTS_DP, fts_level=   consider_visiting (early): `./c': fts_info=FTS_DP, fts_level=
consider_visiting (late): `./c': fts_info=FTS_DP, isdir=1 ign   consider_visiting (late): `./c': fts_info=FTS_DP, isdir=1 ign
consider_visiting (early): `.': fts_info=FTS_DP, fts_level= 0   consider_visiting (early): `.': fts_info=FTS_DP, fts_level= 0
consider_visiting (late): `.': fts_info=FTS_DP, isdir=1 ignor   consider_visiting (late): `.': fts_info=FTS_DP, isdir=1 ignor
./c/a/c                             ./c/a/c

If you notice, there's a gap in Stephane's approach that mine doesn't have. Even with the prune. I think this shows that his method is avoiding extra work in walking into directories that it should otherwise be ignoring.

11
  • That still causes find to descend into the p directories though. Commented Jun 3, 2013 at 7:20
  • Yes, as -prune can't prune in this situation, filtering maybe the only option left.
    – Bohr
    Commented Jun 3, 2013 at 7:35
  • @StephaneChazelas, would something like this address your point? find -mindepth 3 -type d -path '*/p/*' -prune -o -name c -print.
    – slm
    Commented Jun 3, 2013 at 7:35
  • Yes, that's exactly right. I forgot I can prune the path! Thank you! (This should be added to your answer.)
    – Bohr
    Commented Jun 3, 2013 at 7:45
  • @Bohr, just updated it.
    – slm
    Commented Jun 3, 2013 at 7:54
0

According to the man page of find:

 -prune True;  if  the  file is a directory, do not descend into it. If
        -depth is given, false; no  effect.

So in your particular case I would do something like:

 find a/* -mindepth 2  -type f -print

But of course there is not always such an easy solution.

1
  • Sorry I should make it more clear!
    – Bohr
    Commented Jun 3, 2013 at 7:04

You must log in to answer this question.

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