Bash – use ‘find’ to search for directories !containing certain filetype foo

bashdirectoryfind

I have a few directories, some with a depth of 3, which contain mixed file types. What I need to do is to rm -rf all the subdirectories that do not contain filetype foo.

Is this achievable with find somehow?
I do know that I can use find like this:

find . ! -name '*.foo' -delete

to delete all files within the directories that do not contain any file of type *.foo.
Now, how can I use this, to not only delete all unwanted files, but all directories and subdirectories which do not contain *.foo?

Best Answer

(Your question is not clear: if a directory contains some.foo and some.bar, should it be deleted? I interpreted it as requiring such a directory to be kept.)

The following script should work, provided that no file name contains a newline and no directory matches *.foo. The principle is to traverse the directory from the leaves up (-depth), and as *.foo files are encountered, the containing directory and all parents are marked as protected. Any reached file that is not *.foo and not protected is a directory to be deleted. Because of the -depth traversal order, a directory is always reached after the *.foo files that might protect it. Warning: minimally tested, remove the echo at your own risk.

find . -depth -name '*.foo' -o -type d | awk '{
    if ($0 ~ /\.foo$/) {
        while (sub("/+[^/]+$", "")) {protect[$0]=1;}
    } else {
        if (!protect[$0]) {
            gsub("[\\\001-/]", "\\\\&"); # protect file names for xargs
            print;
        }
    }
}' | xargs echo rm -rf

For once, I'm not proposing a zsh solution.