When running `rm -rf`, is it possible to exclude certain subdirectories?
Solution 1
Maybe with find + xargs + rm combination?
find /space ! -iregex '(var_opt|var_log)' | xargs rm -f
or something in that tune. Of course, it might be wise to first instruct xargs execute something more harmless, such as echo, before changing it to rm ...
Solution 2
Simple conceptually, and has a low risk of error:
mkdir TO_DELETE
mv * TO_DELETE
mv TO_DELETE/var_opt TO_DELETE/var_log .
rm -rf TO_DELETE
Ignore the error from mv
about moving TO_DELETE
to a subdirectory of itself.
You can also use ksh's extended globs:
rm -rf !(var_opt|var_log)
These are also available in bash if you enable them:
shopt -s extglob
rm -rf !(var_opt|var_log)
Ditto in zsh:
setopt ksh_glob
rm -rf !(var_opt|var_log)
Zsh also has its own extended globs:
setopt extended_glob
rm -rf ^var_(opt|log)
Solution 3
If your input file names are generated by users, you need to deal with surprising file names containing space, ', or " in the filename.
The use of xargs
can lead to nasty surprises because of the separator problem.
GNU Parallel does not have that problem.
find /space ! -iregex '(var_opt|var_log)' | parallel -X rm -f
Watch the intro video for GNU Parallel to learn more.
Solution 4
If the directories you want to preserve are exactly the mountpoints, you might be able to use --one-file-system
in GNU rm
.
I haven't investigated how this is implemented, but I'm guessing that this won't do what you want if the bind mount is from within the same filesystem, so be careful! rm
doesn't have a --no-act
option, but you can pipe yes no | rm -ir .
for example.
David Yates
I'm a hobbyist programmer, part-time sysadmin, and full-time analytics, big data, data center management, automation, and cloud computing architect and delivery engineer.
Updated on September 17, 2022Comments
-
David Yates almost 2 years
I routinely use bind mounts to aid in making space available in multiple locations without having to have multiple logical volumes / physical partitions / LUNs, etc.
For example, I may have a 200G LV mounted at
/space
. From there, I will make subdirectories likevar_opt
andvar_log
which I can then bind mount to/var/opt
and/var/log
, respectively.When doing a cleanup on the 'space' directory, is it possible to exclude directories from an
rm -rf
running inside/space
?Example:
# pwd /space # rm -rf * {except-for-var_opt-and-var_log}
Is there a different or better (but similarly simple) way to accomplish what I'm trying to do that I haven't thought of?
-
David Yates almost 14 yearsdidn't think of that! good idea :)
-
Gilles 'SO- stop being evil' almost 14 yearsDo not use xargs (except with
-0
)! It expects input quoted in a highly peculiar way thatfind
does not generate. So this command will fail horribly if there are file names containing spaces or\'"
. Instead, use-exec
: find /space ! -iregex '(var_opt|var_log)' -exec rm {} +. Or since
-iregex` is specific to GNU find anyway, use its-delete
action:find /space ! -iregex '(var_opt|var_log)' -delete
. -
David Yates over 4 yearsThat doesn't help at all if the directories are actively bind-mounted
-
alper about 4 yearsshould
TO_DELETE
be on different than the files/folders's parent folder? -
Gilles 'SO- stop being evil' about 4 years@alper No. That would increase the risk of a typo and wouldn't work if the directory is a mount point.
-
Gilles 'SO- stop being evil' about 4 years@warren How do bind mounts affect either of the methods in my answer?
-
David Yates about 4 years@Gilles'SO-stopbeingevil' - if you've bind-mounted something, you can end up deleting it out from under yourself by deleting in the "original" (or bound) location, and it disappearing in the other. That may be expected behavior, but all too often, I've found, it's a surprise. Plus, you cannot move a bind mounted directory elsewhere :)
-
Gilles 'SO- stop being evil' about 4 years@warren You can move a directory that's bind-mounted elsewhere. You can't move a mount point. But in any case you wouldn't end up deleting
var_opt
andvar_log
. -
David Yates about 4 years@Gilles'SO-stopbeingevil' - that's gotta be a recent change - any time I tried to move a bind-mounted base directory, it's promptly broken whatever was access the other location (through at least RHEL 7)