0

Let's say I have a list of nested directories that looks like this:

./x1/mf/dir1
./x1/mf/dir2
./x1/mf/file1
./x2/mf/dir3
./x2/mf/file2
...

I want to remove all the subdirectories of every mf directory. Meaning dir1, dir2, dir3 in the previous example.

I know that

find . -type d -name "mf"

will return a list of all the directories called mf. And ls -d */ returns all the subdirectories in the current directory. So I tried

find . -type d -name "mf" -exec ls -d /* {} \;

to list the desired directories, but it would actually print the directories inside /. I was planning to pipe the resulting list to xargs rm -r to do the removal afterwards.

1
  • try find . -type d -path '*/mf/*' and then add -exec rm -r {} +....
    – Sundeep
    Commented May 16, 2017 at 16:07

2 Answers 2

2

Setting up test directories and files:

$ mkdir -p x{1..3}/mf/dir{1..3}
$ touch x{1..3}/mf/file{1..3}
$ tree
.
|-- x1
|   `-- mf
|       |-- dir1
|       |-- dir2
|       |-- dir3
|       |-- file1
|       |-- file2
|       `-- file3
|-- x2
|   `-- mf
|       |-- dir1
|       |-- dir2
|       |-- dir3
|       |-- file1
|       |-- file2
|       `-- file3
`-- x3
    `-- mf
        |-- dir1
        |-- dir2
        |-- dir3
        |-- file1
        |-- file2
        `-- file3

Then find all directories that has mf in its path and delete them. The -depth does a depth-first traversal, so that find doesn't try to enter directories that it has already deleted. We also print the names of all directories that are deleted.

$ find . -depth -type d -path "*/mf/*" -print -exec rm -rf {} +
./x1/mf/dir1
./x1/mf/dir2
./x1/mf/dir3
./x2/mf/dir1
./x2/mf/dir2
./x2/mf/dir3
./x3/mf/dir1
./x3/mf/dir2
./x3/mf/dir3

Now:

$ tree
.
|-- x1
|   `-- mf
|       |-- file1
|       |-- file2
|       `-- file3
|-- x2
|   `-- mf
|       |-- file1
|       |-- file2
|       `-- file3
`-- x3
    `-- mf
        |-- file1
        |-- file2
        `-- file3
4
  • Which destro are you using? I tried the command on Ubuntu and got: find: warning: the -d option is deprecated; please use -depth instead, because the latter is a POSIX-compliant feature. find: paths must precede expression: . with no output. (I can't get the comment formatting right :P )
    – diaa
    Commented May 17, 2017 at 16:39
  • @ditek This happened to be specific to the find on OpenBSD, but I have updated the answer to work with GNU/POSIX find too.
    – Kusalananda
    Commented May 17, 2017 at 16:42
  • It works now, thanks. I was wondering about the + at the end of the command. I usually use ';'. Is there any difference?
    – diaa
    Commented May 17, 2017 at 16:51
  • The difference is that with \; the rm would be executed once for each found directory, while with + it would be executed once with as many directories as possible (if there were thousands, several rm runs would still be done, but not once per directory).
    – Kusalananda
    Commented May 17, 2017 at 16:57
0

I strongly suggest using this to ls before rm -fring for obvious reasons:

find . -type d -name "mf" -print0 | xargs -0 -n1 -I haystack find haystack -type d -exec rm -fr {} \;

Example:

$ tree
.
├── bar
│   ├── foo
│   │   ├── bar
│   │   └── baz
│   └── freeble
├── baz
│   ├── foo
│   │   ├── bar
│   │   └── baz
│   └── freeble
└── quux
    ├── foo
    │   ├── bar
    │   └── baz
    └── freeble

15 directories, 0 files
$ find . -type d -name "foo" -print0 | xargs -0 -n1 -I haystack find haystack -type d -maxdepth 0 -exec rm -fr {} \;
$ tree
.
├── bar
│   └── freeble
├── baz
│   └── freeble
└── quux
    └── freeble

6 directories, 0 files
6
  • why not just find . -type d -name "mf" -exec rm -rf {} \;? Also, in your example you use foo and bar, but your suggestion does not. The solution you propose and the example you give should be consistent.
    – Centimane
    Commented May 16, 2017 at 16:11
  • @Centimane Only the subdirectories of the mf directories were to be deleted, not the files of the mf directories.
    – Kusalananda
    Commented May 16, 2017 at 16:19
  • Your example swaps mf with foo, and the directory foo was deleted.
    – Centimane
    Commented May 16, 2017 at 16:29
  • Still begs the question why you didn't take the simpler: find . -type d -name "mf" -exec rm -rf {}/* \;
    – Centimane
    Commented May 16, 2017 at 16:30
  • 1
    @Kusalananda my mistake!
    – Centimane
    Commented May 16, 2017 at 16:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .