3

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 {} \;

and

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.

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

5 Answers 5

1

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.

#!/path/to/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.

2
  • 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, 2014 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, 2014 at 8:40
0
rm -rf MyTargetDir && mkdir MyTargetDir

It should do what you are trying to do.

1
  • Not quite: mkdir makes the directory in the CWD, i.e., where 'find' command was issued.
    – BTA
    Jul 31, 2014 at 2:37
0

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

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

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.

5
  • 1
    Use quotes around the $MyTargetDir variable to avoid catastrophes
    – Darkhogg
    Jul 31, 2014 at 8:26
  • I think you'll need a bit more to make sure that dotfiles are removed as well.
    – BowlOfRed
    Jul 31, 2014 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. Jul 31, 2014 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, 2014 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, 2014 at 10:35
0

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 "{}"/*' \;
-1

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

1
  • The option 'r' must be present: I need to make sure the deletion is is recursive on the target directory.
    – BTA
    Jul 31, 2014 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.