Reputation: 466
I have this command:
find ~/Desktop/testrm -mindepth 1 -path ~/Desktop/testrm/.snapshot -o -mtime +2 -prune -exec rm -rf {} +
I want it to work as is, but it must avoid to remove a specific directory ($ROOT_DIR/$DATA_DIR).
Upvotes: 0
Views: 183
Reputation: 27215
You can exclude individual paths using the short circuiting behavior of -o
(like you already did with ~/Desktop/testrm/.snapshot
).
However, for each excluded path you also have to exclude all of its parent directories. Otherwise you would delete a/b/c
by deleting a/b/
or a/
with rm -rf
.
In the following script, the function orParents
generates a part of the find
command. Example:
find $(orParents a/b/c) ...
would run
find -path a/b/c -o -path a/b -o -path a -o ...
.
#! /usr/bin/env bash
orParents() {
p="$1"
while
printf -- '-path %q -o' "$p"
p=$(dirname "$p")
[ "$p" != . ]
do :; done
}
find ~/Desktop/testrm -mindepth 1 \
$(orParents "$ROOT_DIR/$DATA_DIR") -path ~/Desktop/testrm/.snapshot -o \
-mtime +2 -prune -exec rm -rf {} +
Warning: You have to make sure that $ROOT_DIR/$DATA_DIR
does not end with a /
and does not contain glob characters like *
, ?
, and []
.
Spaces are ok as printf %q
escapes them correctly. However, find -path
interprets its argument as a glob pattern independently. We could do a double quoting mechanism. Maybe something like printf %q "$(sed 's/[][*?\]/\\&/' <<< "$p")"
, but I'm not so sure about how exactly find -path
interprets its argument.
Alternatively, you could write a script isParentOf
and do ...
find ... -exec isParentOf "$ROOT_DIR/$DATA_DIR" {} \; -o ...
... to exclude $ROOT_DIR/$DATA_DIR
and all of its parents. This is probably safer and more portable, but slower and a hassle to set up (find -exec bash -c ...
and so on) if you don't want to add a script file to your path.
Upvotes: 1