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? 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:

LC_ALL=C 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 in this case, simply:

LC_ALL=C find . -name p -prune -o -path './*/*/c' -print 

(no point for -type d, -prune would not have any effect on any other type of file and here non-directory files named p are rejected by -path './*/*/c' anyway).

Or with rawhide:

rh -m3 -e '"p" && prune || "c"' 

(with rh, as opposed to find, -mindepth only affects what's reported, not the tests that are made).

Or with zsh:

setopt extendedglob print -rC1 -- ^p/^p/(^p/)#c(ND) 

though the first two ^p follow symlinks to directories. An alternative that wouldn't:

setopt extendedglob print -rC1 -- (^p/)#c~^*/*/*(ND) 

That is c files inside any number (#) of non-p directories, except (~) where the path would not (^) have at least 3 path components.

3
  • Just curious, why do you say this way is the "standard" way? Because you used -o instead of -or? 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. 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. 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. 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.) Commented Jun 3, 2013 at 7:45
  • @Bohr, just updated it. 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! Commented Jun 3, 2013 at 7:04

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.