8

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.

6

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
  • Great explanation. Too many keystrokes for me though... – Elder Geek Jul 29 '16 at 21:53
  • 1
    find is a good friend here, but Bash's for and test are better friends... >:-D – Byte Commander Jul 29 '16 at 22:10
8

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
  • It is amazing to know about this feature. It works great after I ssh and manually run but I get ` "-bash: line 1: syntax error near unexpected token ('" when I run it remotely via ssh $VM_ADDRESS "rm -rf $APP_FOLDER/!(node_modules)". Any ideas? Thanks a lot. – Renato Gama Apr 13 '17 at 18:58
  • @renatoargh the extglob shell option is only enabled for interactive shells - not sure if you can force ssh to do that – steeldriver Apr 13 '17 at 19:33
5

One easy way would be to use trash-cli

you can install it with sudo apt-get install trash-cli

once installed you can navigate to the parent directory A with cd /A and then issue the command trash B D where B and D are the directories you want to remove (they will end up in the trash bin for the drive they are on so if you make a mistake you can recover the files)

Tested under Ubuntu 16.04 and 14.04

4

Simply use Bash's for loop and test to filter the desired directories and the rm -rf command to recursively delete directories, like this:

for x in /path/to/parent/*; do test "$x" != "dir_survive" && rm -rf "$x"; done

This iterates over all elements (files and directories) inside /path/to/parent/ and deletes the element recursively if its name is not equal to dir_survive. If the parent directory is the current directory, you may only write * as path.

If you are unsure and want to test which elements would get deleted first without taking any action, simply replace the rm -rf in the command above with echo and it will only output the delete candidates.

Here's an example run:

$ tree
.
├── dir1
│   ├── subdir1
│   │   ├── file1
│   │   └── file2
│   └── subdir2
│       ├── file1
│       └── file2
├── dir2
│   ├── subdir1
│   │   ├── file1
│   │   └── file2
│   └── subdir2
│       ├── file1
│       └── file2
└── dir_survive
    ├── subdir1
    │   ├── file1
    │   └── file2
    └── subdir2
        ├── file1
        └── file2

9 directories, 12 files

$ for x in *; do test "$x" != "dir_survive" && rm -rf "$x"; done

$ tree
.
└── dir_survive
    ├── subdir1
    │   ├── file1
    │   └── file2
    └── subdir2
        ├── file1
        └── file2

3 directories, 4 files

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.