I'd like to find and delete the contents while leaving the directories themselves intact.

The following

find /data1 -name MyTargetDir -type d -exec rm -rv {} \;


find /data1 -name MyTargetDir -type d | xargs -r rm -vfr

delete all files and directories under 'MyTargetDir' and 'MyTargetDir' as well.

I'd like to leave the directory, but empty.

  • Umm, why don't you then just delete all non-directories? Like find <dir> ! -type d -exec rm {} + – countermode Jul 31 '14 at 23:04

Recreating the directory seems a pretty clean way to do it.

find /data1 -name MyTargetDir -type d -exec rm -rv {} \; -exec mkdir {} \;

You could instead use a subshell in the exec to run a rm -rf * (or similar) from within the directory. But that just seems more trouble than the above. You have the side effect of cleaning up the directory size if that were ever a problem.

As mentioned, recreating the directory may be too much of a problem. If so, an alternative could be:

find /data1 -name MyTargetDir -type d -exec bash "-c" "cd {} && rm -r -- * .*" \;

This has the unfortunate problem of whining about attempts to remove "." and "..", but it should be safe.

Otherwise, you can just go for a full-on script solution, such as perl.

use strict;
use warnings;
use File::Find;
use File::Path qw/remove_tree/;

my ($dir_to_check, $name_to_remove) = @ARGV;
find(\&wanted, $dir_to_check);
sub wanted {
  if (-d and $_ eq $name_to_remove) {
    remove_tree($_, {keep_root => 1});

Pass in the directory first and the name to match second. It's no longer a shell one-liner, but it works, doesn't destroy the directory, and doesn't spit out any spurious warnings.

| improve this answer | |
  • 1
    Running mkdir will recreate the directory with the owner being the current user, the group being the current user's group, and the permissions being whatever umask is set to. That may leave the directory with the same ownership and permissions as previously, but it is certainly not guaranteed, and that may lead to issues if other users need to use that directory. – Warwick Jul 31 '14 at 8:07
  • Correct. It's a race between whether or not recreating the directory is undesirable vs the complexity of retaining. I'll add in a "complex" option if that is necessary. – BowlOfRed Jul 31 '14 at 8:40
rm -rf MyTargetDir && mkdir MyTargetDir

It should do what you are trying to do.

| improve this answer | |
  • Not quite: mkdir makes the directory in the CWD, i.e., where 'find' command was issued. – BTA Jul 31 '14 at 2:37

No doubt there are nicer ways of doing it, but this should work:

for MyTargetDir in `find /data1 -name MyTargetDir -type d -depth`
   if [ $MyTargetDir != "" ]; then
     rm -rfvi $MyTargetDir/*

The if statement is required in case you never find the directory that you are looking for in which case the rm command would destroy your root file system. For this reason, in case there is a bug in what I have written, I have also specified the i option so that you will get warning before command starts removing files; once you are satisfied that it works as intended, you can remove the i option.

| improve this answer | |
  • 1
    Use quotes around the $MyTargetDir variable to avoid catastrophes – Darkhogg Jul 31 '14 at 8:26
  • I think you'll need a bit more to make sure that dotfiles are removed as well. – BowlOfRed Jul 31 '14 at 9:10
  • This doesn't work if you have file names containing whitespace. @Darkhogg It's not enough to quote $MyTargetDir: many problematic file names will already be destroyed by the command substitution. – Gilles 'SO- stop being evil' Jul 31 '14 at 22:59
  • @mikeserv - Feel free to edit my solution. I don't understand what you are suggesting for me to do, and the problem that I need to solve. Thanks. – Warwick Aug 4 '14 at 10:30
  • @Warwick - in fact, I don't fully either. The problem is that you need a reliable delimiter - and you don't have one. It's why for in $(find) doesn't work in the longrun. In order to do it robustly you would have to delimit with $IFS, but that might require a little precognition. – mikeserv Aug 4 '14 at 10:35

Can't think of a way to expand the glob in -exec, but putting it in a subshell should work.

find /data1 -name MyTargetDir -type d -exec bash -c 'shopt -s dotglob; rm -rv "{}"/*' \;
| improve this answer | |

Or you could try this command without the r option in rm. so it don't will be able to remove directories.

| improve this answer | |
  • The option 'r' must be present: I need to make sure the deletion is is recursive on the target directory. – BTA Jul 31 '14 at 2:45

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.