How to delete directories based on `find` output?

I issue the following command to find the .svn directories:

find . -name ".svn"

That gives me the following results:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

How could I process all these lines with rm -fr in order to delete the directories and their content?

Asked By: Arnaud

||

Find can execute arguments with the -exec option for each match it finds. It is a recommended mechanism because you can handle paths with spaces/newlines and other characters in them correctly. You will have to delete the contents of the directory before you can remove the directory itself, so use -r with the rm command to achieve this.

For your example you can issue:

find . -name ".svn" -exec rm -r "{}" ;

You can also tell find to just find directories named .svn by adding a -type d check:

find . -name ".svn" -type d -exec rm -r "{}" ;

Warning Use rm -r with caution it deletes the folder and all its contents.

If you want to delete just empty directories as well as directories that contain only empty directories, find can do that itself with -delete and -empty:

find . -name ".svn" -type d -empty -delete
Answered By: Drav Sloan

Bash specific solution:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion
Answered By: rush

Here is a portable still faster than the accepted answer way.

Using a + instead of a semicolon as find command terminator is optimizing the CPU usage. That can be significant if you have a lot of .svn sub-directories:

find . -name .svn -type d -exec rm -rf {} +

Note also that you never1 need to quote the curly braces here.

1 Unless you use the fish shell (this might have been fixed since I wrote this reply).

Answered By: jlliagre

Assume you are using gnu find, you can use the -delete option:

find . -name test -delete

which is easier to remember.

Answered By: Chun Yang

On my computer when I use:

find . ( -name dirname -type d ) -exec rm -r '{}' ';'

The directories are deleted but I get the error:

find: ‘./dirname’: No such file or directory

for each directory.

My directories aren’t empty, so the -delete option won’t work for me. I found the reason for this behavior here:

  1. find takes (not necessarily) the first entry in the ./ directory. this would be e.g. dir.1/
  2. it compares it to the pattern ‘dir.?’. does it match? yes.
  3. find executes “rm -r dir.1”.
  4. find tries to enter dir.1/ to find the pattern within the directory. it doesn’t know anything about the exec command.
  5. it doesn’t find dir.1/ anymore. returns ENOENT (look at the strace output)

I used this instead to work around:

rm -r `find . -name dirname -type d`

Keep in mind that find will still try to recurse into directories named dirname, which isn’t really necessary and will take some additional time. Depending on your directory structure, you might be able to work around this with the --depth find option. In addition, if you have a directory structure like dirname/foo/dirname you will get “No such file or directory” errors from rm. To suppress the errors you can redirect stderr to /dev/null or use the -f (force) flag with rm.

Answered By: Samuel

A faster way to do this is:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

In case you have “.svn” inside another “.svn”.

Answered By: Johann Chang

I’ve found that the -delete action does work nicely with the -path test. For instance, the following ought to work on the original posters problem:

find . -path '*/.svn*' -delete

Note that in addition to deleting ‘.svn’ directories (and their contents), this will also delete any files or directories whose names start with ‘.svn’. For example, if you used -path '*/.git*' it would also delete ‘.gitignore’ and ‘.gitattribute’ in addition to ‘.git/’. To avoid that, and just delete directories with that exact name use:

find . -path '*/.svn/*' -or -name '.svn' -delete

Note the slash after .svn. This will first find, and delete, all the files under ‘.svn’, then delete the .svn directory itself.

Answered By: Magnus

TLDR

find . -name .svn -prune -execdir rm -rf {} +

Details

Use -execdir, not -exec

From man find:

There are unavoidable security problems surrounding use of the -exec action; you should use the -execdir option instead.

In most case, -execdir is a drop-in replacement for -exec.

Use +, not ;

From man find:

As with the -exec action, the `+’ form of -execdir will build a command line to process more than one matched file, but any given invocation of command will only list files that exist in the same subdirectory.

When looking for an exact name match, + and ; will do the same, as you cannot have two files with the same name in the same directory, but + will provide increased performance when several files/directories match your find expression within the same directory.

Also, ; needs escaping from your shell, + does not.

Use -prune

From man find:

-prune: True; if the file is a directory, do not descend into it.

This avoid searching a directory that we want to delete. Obviously, it needs to be put after the name test. See:

$ mkdir -p test/foo/bar
$ find test -name foo -execdir rm -rf {} +
find: ‘test/foo/bar’: No such file or directory

Versus:

$ mkdir -p test/foo/bar
$ find test -name foo -prune -execdir rm -rf {} +
# no error
Answered By: Étienne Miret

Short and simplest solution is to use xargs here

find . -name ".svn" | xargs rm -rf
Answered By: Jeegar Patel
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.