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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to delete all the files in the current directory tree, except those in save. I ran this command:

 find . \( -name save -prune \) -o -type f -ls | grep /save/

and it found none. But when I ran this command:

 find . \( -name save -prune \) -o -type f -delete

All those files in /save/ were gone. What am I missing?

share|improve this question
3  
Ouch ... I learned something today (thanks to you). And I recommend a simple mv save/ ../some/safer/location prior to such a "generic" delete command (... but of course, prior to your post I'd have done the same check and ran into the same trouble!). Now go find a good "undelete" for the filesystem the files were on ^^ – Olivier Dulac Jan 21 at 14:50
2  
My pain is your prevention. – Otheus Jan 21 at 15:16
    
1000 thanks to you. Code (often?) works in mysterious ways... – Olivier Dulac Jan 21 at 16:52
2  
related: unix.stackexchange.com/questions/87258/… – lesmana Jan 21 at 19:57
    
@lesmana I upvoted your answer there. sadly, my version of find doesn't give me such a nice warning :( – Otheus Jan 22 at 10:14
up vote 26 down vote accepted

-delete implies -depth that doesn't work with -prune (-depth starts with the leaves). There's a warning about that in the manual of the GNU version (-delete is a GNU extension now also supported by FreeBSD find).

info find --index-search=-delete

The use of the '-delete' action on the command line automatically turns on the '-depth' option (*note find Expressions::). This can be surprising if you were previously just testing with '-print', so it is usually best to remember to use '-depth' explicitly.

info find --index-search=-prune

Because '-delete' implies '-depth', using '-prune' in combination with '-delete' may well result in the deletion of more files than you intended.

Here, you've got the option of either using rm instead:

find . -name save -prune -o -type f -exec rm -f {} +

(potentially unsafe if there are directory writeable by others in there, as one could make you delete files outside the current directory tree by replacing directories with symlinks while you run that command).

A safer alternative:

find . -name save -prune -o -type f -execdir rm -f -- {} \;

That doesn't have the problem mentioned above but means running one rm per file. The -- is necessary for the FreeBSD implementation, not the GNU one that prefixes file names with ./.

Alternatively, as suggested by Costas:

LC_ALL=C find . ! -name save ! -path '*/save/*' -type f -delete

(but that still needlessly descends into save directories)

The LC_ALL=C is there so * matches any sequence of bytes (even those that don't form valid characters in the current locale). Note that it will affect the language of error messages (English instead of the language of the user).

share|improve this answer
    
What's the security issue here with rm? – jrw32982 Jan 26 at 21:10
    
@jrw32982, see edit with link to the GNU find manual – Stéphane Chazelas Jan 27 at 11: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.