1

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:

Parent001_dir
   001_boo
   002_hugs
   003_foobar
   004_doobar
   005_apple
   ...

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/
do
find !-name "*foobar*" -o !-name "*doobar*"  -delete
done

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

Parent001_dir
   003_foobar
   004_doobar

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 '15 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] – Jordan Garner Oct 2 '15 at 20:24
  • Check the output before rushing off to delete: What does find ! -name '*foobar*' -o ! -name '*doobar*' say? – muru Oct 2 '15 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] – Jordan Garner Oct 2 '15 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 '15 at 20:39
2

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

or

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"; 
done

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",
        entry->fts_accpath);

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 '15 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 '15 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 – Jordan Garner Oct 2 '15 at 20:43
  • 1
    @JordanGarner what did you run? What's the actual path you are using? What is your OS? – terdon Oct 2 '15 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? – Jordan Garner Oct 2 '15 at 20:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.