Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question
    
I take it that d and e are files, not directories? –  Anthon Jun 3 '13 at 6:57

3 Answers 3

up vote 0 down vote accepted

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.

share|improve this answer
    
That still causes find to descend into the p directories though. –  Stéphane Chazelas Jun 3 '13 at 7:20
    
Yes, as -prune can't prune in this situation, filtering maybe the only option left. –  Bohr Jun 3 '13 at 7:35
    
@StephaneChazelas, would something like this address your point? find -mindepth 3 -type d -path '*/p/*' -prune -o -name c -print. –  slm Jun 3 '13 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 Jun 3 '13 at 7:45
    
I wish I could accept the comment as the answer... –  Bohr Jun 3 '13 at 7:49

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
share|improve this answer
    
Just curious, why do you say this way is the "standard" way? Because you used -o instead of -or? –  slm Jun 3 '13 at 7:17
    
@slm, the last sentence should make it clear. –  Stéphane Chazelas Jun 3 '13 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 Jun 3 '13 at 7:23

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.

share|improve this answer
    
Sorry I should make it more clear! –  Bohr Jun 3 '13 at 7:04

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.