Right now I backup the mysql databases using a cronjob everyday. Now that the server is getting full, I only want to keep one backup for every month, one backup from sunday every week and the last 7 backups.

My backup files look like this (in a directory /var/backup):


This serverfault post: https://serverfault.com/a/643335/274380 helped me to create the shell script and how to determine the correct days and put them in an array.

I altered the script from above post a little bit and here is it:

for i in {0..7}; 
index=$(date +"%Y%m%d" -d "-$i day");
value=$(date +"%Y-%m-%d" -d "-$i day");

for i in {0..4}; 
index=$(date +"%Y%m%d" -d "sunday-$((i+1)) week");
value=$(date +"%Y-%m-%d" -d "sunday-$((i+1)) week");

for i in {0..12}; 
        DW=$(($(date +%-W)-$(date -d $(date -d "$(date +%Y-%m-15) -$i month" +%Y-%m-01) +%-W)))
        for (( AY=$(date -d "$(date +%Y-%m-15) -$i month" +%Y); AY < $(date +%Y); AY++ )); do
                ((DW+=$(date -d $AY-12-31 +%W)))
index=$(date +"%Y%m%d" -d "sunday-$DW weeks");
value=$(date +"%Y-%m-%d" -d "sunday-$DW weeks");

echo ${keep[@]};

output is:

2014-05-04 2014-06-01 2014-07-06 2014-08-03 2014-09-07 2014-10-05 2014-11-02 2014-12-07 2015-01-04 2015-02-01 2015-03-01 2015-04-05 2015-04-26 2015-05-03 2015-05-10 2015-05-17 2015-05-20 2015-05-21 2015-05-22 2015-05-23 2015-05-24 2015-05-25 2015-05-26 2015-05-27

So my question is, based on ${keep[@]} how to keep the files which dates are in ${keep[@]} and delete the rest?

Thank you in advance!

migrated from serverfault.com May 28 '15 at 6:23

This question came from our site for system and network administrators.


This is how I would do this:

find /var/backup/ -type f -maxdetph 1 $(printf "! -name %s " ${keep[*]}) \
  -exec rm {} \;

Note that this will not work if your file names have spaces in them.

  • It won't work as expected, you need wildcard path matchings. And you cannot pass escaped characters to find args in a trivial way. – yaegashi May 28 '15 at 3:18

How about using grep -vE with the following expression:

$ echo "$(IFS=\| && echo "${keep[*]}")"

So you can do like this:

ls /var/backup/* | grep -vE "$(IFS=\| && echo "${keep[*]}")" | xargs -r rm

Updated: If you prefer using find:

find /var/backup -maxdepth 1 -type f | grep -vE "$(IFS=\| && echo "${keep[*]}")" | xargs -r rm

Or more complicated one:

find /var/backup -maxdepth 1 -type f -regextype posix-egrep ! -regex ".*($(IFS=\| && echo "${keep[*]}")).*" -print0 | xargs -0r rm
  • perfect thank you! do you have a solution with "find" instead of "ls" because as I see everybody discourages the use of "ls" together with xargs and encourages the use of "find". – Petros Mastrantonas May 27 '15 at 14:17
  • I posted an answer using find. – moebius_eye May 27 '15 at 19:09
  • Updated my answer. – yaegashi May 28 '15 at 3:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy