I am trying to delete all sub directories (and files inside) that do not contain one of two patterns in the directory name using Bash on OSX. I am trying to do this recursively - for a bunch of parent directories.

Lets say the pattern in sub dirs I want to not delete is either "foobar" or "doobar"

I have a whole bunch of Parent directories, like this one:


I want to run a for loop code that will go into each and every parent dir and delete the non-matching sub dirs.

Code I thought could work:

for i in /path/to/parent/directories/
find !-name "*foobar*" -o !-name "*doobar*"  -delete

But I read the find manual and see no option for not matching patterns; !-name isn't an option.

EDIT- from comments, trying:

find /path/to/parent/directories/ -type d -not -name "*foobar*" -not -name "*doobar*"  -delete

and getting a"path potentially not safe" message

If I find a way to fix my code, I could finally get "Parent001_dir" and all other parent dirs to look like:'


Are there wildcard characters that could fix my code maybe? Or should I use another approach entirely? Thanks in advance for any help.

  • It's ! -name - with a space in between, but the more recommended option is -prune, from what I can tell.
    – muru
    Oct 2, 2015 at 19:57
  • I added the space, but now terminal gives me this (and doesn't delete anything): usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]; find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression] Oct 2, 2015 at 20:24
  • Check the output before rushing off to delete: What does find ! -name '*foobar*' -o ! -name '*doobar*' say?
    – muru
    Oct 2, 2015 at 20:32
  • just doing that part gives the same "usage" output - usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression] ; find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression] Oct 2, 2015 at 20:36
  • You don't want the -o. In any case, that should have worked. What OS are you running? It looks like your find doesn't support !. Try with -not as in my answer below.
    – terdon
    Oct 2, 2015 at 20:39

1 Answer 1


First of all, there;s no need for a loop, find can do all of this itself. You can negate conditions using the ! or -not flags. You also don't want -o since that would mean "find files/dirs whose name is not foobar or whose name is not doobar". That would find everything since one or the other condition will always be true (foobar matches "not doobar" and doobar matches "not foobar"). What you wanted is something like:

find /path/to/parent/dirs/* -type d ! -name "*foobar*" ! -name "*doobar*" -delete


find /path/to/parent/dirs/* -type -d -not -name "*foobar*" -not -name "*doobar*" -delete

You could, if you wish, also do this in the shell. For example, with bash:

for i in /path/to/parent/dirs/*/; do 
    [[ "$i" =~ 'foobar' || "$i" =~ 'doobar' ]] || rm -rf "$i"; 

I'm not sure about the details and I don't have a mac to test this on, but it looks like the OSX find won't let you delete directories. I believe (but am not sure) that that's what this code does:

/* Potentially unsafe - do not accept relative paths whatsoever */
if (strchr(entry->fts_accpath, '/') != NULL)
    errx(1, "-delete: %s: relative path potentially not safe",

One way to get around this is to use -exec instead:

find /path/to/parent/dirs/ -type d ! -name "*foobar*" ! -name "*doobar*"  \
    -exec rm -rf {} +

All of these commands will delete stuff. Test them before use!

  • I think the test for directory can be skipped if you use **/.
    – muru
    Oct 2, 2015 at 20:33
  • 1
    @muru true, thanks. In fact, I don't even need globstar here since the OP only wants directories.
    – terdon
    Oct 2, 2015 at 20:37
  • Thanks for the tips guys. I think im close - now I'm getting a "relative path potentially not safe" msg and it's still not deleting Oct 2, 2015 at 20:43
  • 1
    @JordanGarner what did you run? What's the actual path you are using? What is your OS?
    – terdon
    Oct 2, 2015 at 20:45
  • Thanks again for the help. Using OSX Yosemite, 10.10.5. The actual path is to an external drive: " /Volumes/MRI_data/ENIGMA/840/2R064GH" where 2R064GH is the parent. To test this on just ONE parent dir, I ran "find /Volumes/MRI_data/ENIGMA/840/ -type d -not -name "MPRAGE" -not -name "ep2d" -delete" MPRAGE is foobar and ep2d is doobar. Maybe this is a permission issue? Oct 2, 2015 at 20:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .