Remove all directories from within a parent directory except one and its descendents

directory structure

I want to remove directory B and D. But i want to keep C and all its descendent files and directories. What's the command to remove all children directories of a parent directory except one directory and its children.

Help appreciated.


Solution 1:

Using the bash shell's extended glob features (which are enabled by default in current Ubuntu installations), given

$ tree A
A
├── B
├── C
│   ├── ac1
│   └── ac2
└── D

5 directories, 0 files

you can address everything excluding C and its contents using the glob expression A/!(C) i.e.

$ echo A/!(C)
A/B A/D

So to remove everything except directory C and its contents you can simply use

rm -rf A/!(C)

leaving

$ tree A
A
└── C
    ├── ac1
    └── ac2

3 directories, 0 files

Solution 2:

What you want is this command:

find ~/TESTDIR -mindepth 1 -maxdepth 1 -type d -not \( -name "keepMe" \) -exec rm -rf {} \;

Demo:

# List what's inside directory we want to remove
$ ls
file1  file2  keepMe/  removeA/  removeB/
# Testing what find gives without removing
$ find ~/TESTDIR -mindepth 1 -type d -not \( -name "keepMe" \)               
/home/xieerqi/TESTDIR/removeA
/home/xieerqi/TESTDIR/removeB
# Actual removal and testls
$ find ~/TESTDIR -mindepth 1 -maxdepth 1 -type d -not \( -name "keepMe" \) -exec rm -rf {} \;
$ ls
file1  file2  keepMe/

Explanation:

  • find DIRECTORY call find command to operate upon DIRECTORY
  • -mindepth 1 : work only with contents of the directory , avoid directory itself which is level 0
  • -maxdepth 1 : prevents descending into subdirectories ( rm -rf is recursive anyway, so we don't need to descend into subdirectories to remove them )
  • -type d : search only for directories
  • -not \( -name "keepMe" \) ignore item with the name you want to keep
  • -exec rm -rf {} \; perform removal on each found item