Suppose under the current directory, there are multiple sub-directories, and one is called A.

How to delete all sub-directories except A with Bash?

10 Answers 10


Bash has extended globbing (first test, then remove the echo):

shopt -s extglob
echo rm -rf !(A)
| improve this answer | |
  • (before I forget - you might disable CSH style history completion, in Bash3 there's a bug while ignoring !(. set +H – TheBonsai Jun 4 '09 at 19:38
  • +1 Bash if full of surprises! Sometimes they are nice like this one. – Aleksandr Levchuk Nov 16 '10 at 1:46
  • Wauw very nice indeed! Works as expected. With shopt | grep ext You can see if the plugin is enabled. – danger89 Nov 21 '15 at 21:24
find -maxdepth 1 -type d -not -name A -not -name "." -exec rm -ir {} \;

What about:

mv A /tmp/
rm * -rf
mv /tmp/A .

This avoids some of the "scariness" of a typo in the other commands.

| improve this answer | |
  • 1
    +1 for doing the sane thing instead of hoping the tools are smart enough. still, one night, when i was just learning Linux, i copied the kernel to /tmp before doing my first recompile. it didn't succeed, but erased the old one, so i said 'no sweat, i have a copy' only to find that a midnight cron task had erased it with every file more than a week old in /tmp! i had to recompile again and this time do it right, or no reboot for me! – Javier Jun 4 '09 at 21:16
  • best answer posted :) – warren Nov 16 '10 at 2:59

Something like

find . -type d -not -name A -exec rm -ir {} \;

should do.


It should really be

find . -type d -maxdepth 1 -not -name A -exec rm -ir {} \;

to prevent find from recursing below A.

  • 3
    But, this would also remove any sub-directories below A like A/foo and A/bar, but would preserve A/A. – TCampbell Jun 4 '09 at 19:30
  • Cool! Questions and answert get migrated from SO to SF... but my edit above was lost... – agnul Jun 4 '09 at 19:47
  • It should be better to swap maxdepth and type arguments like this : find . -maxdepth 1 -type d -not -name A -exec rm -ir {} \; – Spawnrider Feb 11 '19 at 14:08

i usually do this by working up an ls command that gets it right first. i'm not at a unix machine, but something like:

ls -lda "[^A]"

Once you get it right, pipe it to a command

ls -lda "[^A]" | xargs rm -rf

Feel free to edit above if I've got my regular expression wrong...

| improve this answer | |

If you want to be more flexible but manual you can do:

ls > /tmp/foo
edit /tmp/foo as you like
xargs -a /tmp/foo rm -r

That way you can do general munging.

| improve this answer | |

Here's one way. Be careful with this sort of thing, though, it's so powerful that it can only be used for good or evil...

find * -type d | grep -v "^A" | xargs rm -rf
| improve this answer | |

Don't use find as some people have shown with -exec and rm without passing -print0 to find and -0 to xargs. It will get confused on file names with spaces or newlines:

$ mkdir 'foo foo'
$ mkdir foo$'\n'foo 
$ find . -type d -exec rm -ir {} \;
rm: cannot remove directory `.'
rm: remove directory `./foo\nfoo'? y
find: `./foo\nfoo': No such file or directory
rm: remove directory `./foo foo'? y
find: `./foo foo': No such file or directory

Instead use find -print0 with xargs -0 , '-exec command {} +', or -delete if your find supports it.

| improve this answer | |

In addition to the earlier example of:

find -maxdepth 1 -type d -not -name A -not -name "." -exec rm -ir {} \;

you can also do:

find some/subdir -mindepth 1 -maxdepth 1 -type d -not -name A -exec rm -ir {} \;

to avoid having to cd some/subdir first.

| improve this answer | |

Your Answer

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