0

I want to list only the directories that are not inside a .git/ directory on my current path.

I'm trying this:

find . -path "**/.git" -prune -o -print -type d

The .git dirs are excluded, but the snippet is also listing files. But it should not as I specified -type d. How to make the find utility behave as I described?

ninrod
  • 389

2 Answers2

3

You've used -print before -type d, so find print all things not satisfied the first expression.

You want to swap them:

find . -path '*/.git' -prune -o -type d -print

or using predicate only, so you can omit -print:

find . ! \( -path '*/.git' -o -path '*/.git/*' \) -type d

Also note that you only need to use one asterisk */.git, double asterisk ** has no special meaning to find pattern matching. And you can make it simpler, more portable and slightly faster by using -name instead of -path:

find . -name .git -prune -o -type d -print
cuonglm
  • 153,898
  • thank you. The first solution worked. However, if I ommit -print, as you suggested, I get .git directories, which I don't want. If i put back the magical -print, than it all works as I want. Why that happens? That's really unexpected. – ninrod Feb 25 '16 at 04:54
  • think I've found the answer here. Without -print the default action applies to all branches, even pruned ones. – ninrod Feb 25 '16 at 04:59
  • Yes, my bad. I am not near my laptop to check. Here omit -print make it to be applied for the whole expression. – cuonglm Feb 25 '16 at 05:22
  • Thanks, now both solutions work fine. With prune I only have to specify */.git while find needs us to say both */.git and */.git/* when using predicate only. Why is that? – ninrod Feb 25 '16 at 12:35
  • Because */.git can not match something like foo/.git/bar. – cuonglm Feb 25 '16 at 12:43
  • Ok, but why */.git matches something like foo/.git/bar in the first case with -prune? – ninrod Feb 25 '16 at 12:49
  • No, It's not pattern matching, -prune prevent find from looking into .git directory, any directories inside were ignored. – cuonglm Feb 25 '16 at 13:10
  • The version without -prune has the downside that find will recurse into .git directories and try every file there. This could be a performance hit. – Gilles 'SO- stop being evil' Feb 25 '16 at 21:31
  • Thank you @Gilles. So -name .git -prune is essentially the same thing as -path '*.git' -prune, but -path has better performance. Is that correct? – ninrod Feb 27 '16 at 13:58
-1

Due to lack of knowledge of the find command, I just use a less efficient but most likely equally useful and probably more readable one-liner that also involves grep:

find . -type d | grep -v "/\.git"
RAKK
  • 1,352
  • It's not equal. It gives wrong result if filename contain newline. – cuonglm Feb 25 '16 at 07:13
  • You'd need grep -Ev '\.git($|/)', otherwise you're ignoring e.g. .gitignore files. And even then that would break on file names containing newlines (this one isn't always a concern in practice). Given that there's a simple find solution, such an alternate method is not called for. – Gilles 'SO- stop being evil' Feb 25 '16 at 21:29