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?

11 Answers 11


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

shopt -s extglob
echo rm -rf !(A)
  • (before I forget - you might disable CSH style history completion, in Bash3 there's a bug while ignoring !(. set +H
    – TheBonsai
    Jun 4, 2009 at 19:38
  • +1 Bash if full of surprises! Sometimes they are nice like this one. Nov 16, 2010 at 1:46
  • Wauw very nice indeed! Works as expected. With shopt | grep ext You can see if the plugin is enabled. Nov 21, 2015 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.

Please be aware to not be in the root (/) folder when running the rm * -rf command above.

  • 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, 2009 at 21:16
  • best answer posted :)
    – warren
    Nov 16, 2010 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, 2009 at 19:30
  • Cool! Questions and answert get migrated from SO to SF... but my edit above was lost...
    – agnul
    Jun 4, 2009 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, 2019 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...


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.


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
  • Actually -v already negates the values, so "^" is not required, it's -v name_to_keep
    – Braikar
    Apr 23, 2021 at 9:11

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.


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.


find ...ROOT_FOLDER.../* -type d | grep -v FOLDER_TO_KEEP | xargs rm -rf

You must log in to answer this question.