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.

  • try find . -type d -path '*/mf/*' and then add -exec rm -r {} +.... – Sundeep May 16 '17 at 16:07
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
  • 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 May 17 '17 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 May 17 '17 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 May 17 '17 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 May 17 '17 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
  • 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 May 16 '17 at 16:11
  • @Centimane Only the subdirectories of the mf directories were to be deleted, not the files of the mf directories. – Kusalananda May 16 '17 at 16:19
  • Your example swaps mf with foo, and the directory foo was deleted. – Centimane May 16 '17 at 16:29
  • Still begs the question why you didn't take the simpler: find . -type d -name "mf" -exec rm -rf {}/* \; – Centimane May 16 '17 at 16:30
  • 1
    @Kusalananda my mistake! – Centimane May 16 '17 at 16:31

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.