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.

This question already has an answer here:

I want to recursively delete all files not accessed in a while in folder a, except all files in the subfolder b.

find a \( -name b -prune \) -o -type f -delete

However, I get an error message:

find: The -delete action automatically turns on -depth, but -prune does nothing when -depth is in effect. If you want to carry on anyway, just explicitly use the -depth option.

Adding -depth causes all files in b to be included, which must not happen.

Anyone know a safe way to make this work?

share|improve this question

marked as duplicate by Michael Kjörling, jasonwryan, Anthon, Renan, slm Aug 18 '13 at 20:11

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
@MichaelKjörling: I had a look at extglob, but how do you include everything under a except a/b? –  forthrin Aug 18 '13 at 18:53
    
Won't cd a && ls -d !(b/*) work? (To do it, just rm -r rather than ls -d.) –  Michael Kjörling Aug 18 '13 at 18:55
    
Your suggestion deletes subfolders. I want to keep the folders intact. I want to find and delete all files in the tree under a (except files under a/b). –  forthrin Aug 18 '13 at 19:16
    
So just skip the -r to rm. It seems what you are asking about is fairly easily answered by using bash's extended globbing, and then what you do with the result of the globbing is up to you. –  Michael Kjörling Aug 18 '13 at 19:24

2 Answers 2

up vote 1 down vote accepted
find a -not -path "*/b*" -type f -delete

note that this will not delete any file which name is starting with b and also any file which has any parent directory which name is starting with b.

i assume that you used a and b as placeholders and the real names are more like secretprojects and foobalator. if you put foobalator in place of b then the amount of false positives will be drastically reduced.

there is still chance for false positives though, but at least they will be not deleted, so it will be not as tragic. furthermore, you can check for false positives by first running the command without -delete.

beware! -delete implies -depth. -depth causes find to process the contents of a directory before the directory itself which affects the outcome drastically. if you run the command without -delete you should explicitly add -depth.

find a -depth -not -path "*/b*" -type f

explanation:

  • -path is required instead of -name because -name only matches against the basename while -path is matching against the entire pathname.
  • -depth (implied by -delete) causes find to process the contents of a directory before the directory itself. this is needed so -delete can delete the directory from inside out. -delete refuses to delete non-empty directories.
  • -prune prevents find from processing the contents of a directory based on some filters. the way -prune and -depth is implemented in find causes -prune to be ineffective when -depth is also in effect.
share|improve this answer
    
-not -path was just the thing! Thanks for a generous explanation! –  forthrin Aug 18 '13 at 18:55

Just use rm instead of -delete:

find a -name b -prune -o -type f -exec rm -f {} +
share|improve this answer

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