Tuesday, October 09, 2012

Delete old files except for certain directories and files with one liner bash

DISCLAIMER: Do understand what you are doing before proceeding. I am not responsible for your own actions. I just make public useful code which might become harmful in the wrong hands.

Here is a one liner "find" command that allows you to iterate through all files inside a given directory providing exceptions for certain files and directories. With the result you can run any command.

Let me read the below example for you: Find starting at /home/ directory all files (-type f) older than 30 days (-mtime +30), print full path file names followed by a NUL character so white spaces are correctly interpreted (-print0), ignoring (-prune) directory "nestor" or any hidden files (.*). Then list (ls) the items terminated by a null character and no-run-if-empty (xargs -0 -r). The "-o" switch says "Do not evaluate the next expression if the previous is true", reason why the exceptions go first.
$ find /home/ -type d -name "nestor" -prune -o -name ".*" -prune -o -type f -mtime +30 -print0  | xargs -0 -r ls -al
Clearly you can change "ls -al" by "rm" if you are confident all those files might go away.

On a related issue it is common to forget to use "-mindepth 1" option which basically tells find "do not list in your 'findings' the start directory". Imagine you want to delete anything below /opt/tmp/realtime_temp. If you do not use the "-mindepth 1" option the directory itself will be deleted as well. So do use the flag if you are not trying to delete the start directory. I have seen some Linux installations delete the dir while others won't ... go figure.
find /opt/tmp/realtime_temp/ -mindepth 1 -mtime +5 -exec rm -Rf {} \; > /dev/null

Another related issue is that 'find' needs the '-depth' flag in order to correctly remove all files and directories matching certain rules (when using -exec or piping to xargs. If using -delete that option implies -depth as per man pages). Not using '-depth' results in errors like 'No such file or directory' as 'find' tries to execute the remove command for files contained in directories that it already removed.
find /opt/tmp/realtime_temp/ -depth -mindepth 1 -mtime +5 -exec rm -Rf {} \; > /dev/null

No comments: