Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

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

5 Answers 5

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.

share|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 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 at 8:40
rm -rf MyTargetDir && mkdir MyTargetDir

It should do what you are trying to do.

share|improve this answer
    
Not quite: mkdir makes the directory in the CWD, i.e., where 'find' command was issued. –  BTA Jul 31 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`
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.

share|improve this answer
1  
Use quotes around the $MyTargetDir variable to avoid catastrophes –  Darkhogg Jul 31 at 8:26
    
I think you'll need a bit more to make sure that dotfiles are removed as well. –  BowlOfRed Jul 31 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 Jul 31 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 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 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 "{}"/*' \;
share|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.

share|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 at 2:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.