Search code examples
bashgnu-findutils

Use find to get all folders that don't have a .git subfolder


How to use find to get all folders that have not a .git folder?

On this structure::

$ tree -a -d -L 2
.
├── a
│   └── .git
├── b
│   ├── b1
│   └── b2
├── c
└── d
    └── .git
        ├── lkdj
        └── qsdqdf

This::

$ find . -name ".git"  -prune -o -type d -print
.
./a
./b
./b/b1
./b/b2
./c
./d
$

get all folders except .git

I would like to get this::

$ find . ...
.
./b
./b/b1
./b/b2
./c
$

Solution

  • It's inefficient (runs a bunch of subprocesses), but the following will do the job with GNU or modern BSD find:

    find . -type d -exec test -d '{}/.git' ';' -prune -o -type d -print
    

    If you're not guaranteed to have a find with any functionality not guaranteed in the POSIX standard, then you might need to take even more of an efficiency loss (to make {} its own token, rather than a substring, by having a shell run the test):

    find . -type d -exec sh -c 'test -d "$1/.git"' _ '{}' ';' -prune -o -type d -print
    

    This works by using -exec as a predicate, running a test that find doesn't have support for built-in.

    Note the use of the inefficient -exec [...] {} [...] \; rather than the more efficient -exec [...] {} +; as the latter passes multiple filenames to each invocation, it has no way to get back individual per-filename results and so always evaluates as true.