35

I'm not sure if this gets the past date within the current day or if it only takes 30 or 31 days to it.

e.g.

If the current date is March 28th, 1 month ago must be February 28th, but what happen when it's March 30th?

Scenario

I want to backup some files each day, the script will save this files within the current date with $(date +%Y%m%d) format, like 20150603_bckp.tar.gz, then when the next month arrives, remove all those files within 1 month ago except the 1st's and the 15th's files, so this is my condition:

past_month = $(date -d "-1 month" +%Y%m%d)
day = $(date +%d)
if [ "$day" != 01 ] && [ "$day" != 15 ]
then
    rm /path/of/files/${past_month}_bckp.tar.gz
    echo "Depuration done"
else
    echo "Keep file"
fi

But I want to know, what will happen when the date is 30th, 31th or even the past February example? It will keep those files? or remove day 1st files?

When it's 31th the depuration will execute, so if the past month only had 30 days, this will remove the day 1st file?

I hope I hinted.

1
  • 2
    Wouldn't you know I'm here on March 30th for this exact reason
    – user7203
    Mar 30, 2018 at 17:02

3 Answers 3

39

- 1 month will subtract one from the month number, and then if the resulting date is not valid (February 30, for example), adjust it so that it is valid. So December 31 - 1 month is December 1, not a day in November, and March 31 - 1 month is March 3 (unless executed in a leap year).

Here's quote from the info page for Gnu date (which is the date version which implements this syntax), which includes a good suggestion to make the arithmetic more robust:

The fuzz in units can cause problems with relative items. For example, 2003-07-31 -1 month might evaluate to 2003-07-01, because 2003-06-31 is an invalid date. To determine the previous month more reliably, you can ask for the month before the 15th of the current month. For example:

    $ date -R
    Thu, 31 Jul 2003 13:02:39 -0700
    $ date --date='-1 month' +'Last month was %B?'
    Last month was July?
    $ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
    Last month was June!

Another warning, also quoted from the info page:

Also, take care when manipulating dates around clock changes such as daylight saving leaps. In a few cases these have added or subtracted as much as 24 hours from the clock, so it is often wise to adopt universal time by setting the TZ environment variable to UTC0 before embarking on calendrical calculations.

3
  • I have a doubt in here, specifically in the February situation... When it's March 29, 30 or 31 it might take the following number of the past month if the current one doesn't exist, so in this three situations it might take March 1st no? Cause if March 29, 30, 31 and then March 1, 2, 3 as you said, then April 1 will be March 4 due to the restructure (I don't know if it's well said) that was made, what do you think?
    – tachomi
    Jun 4, 2015 at 21:40
  • One month before April 1 is March 1 and one month before March 1 is February 1. These are not problems. The problem is that one month before May 31 is May 1 because April 31 doesn't exist. You should check the day number of the one-month-ago date, not the day of the current date.
    – rici
    Jun 4, 2015 at 22:54
  • 2
    Doh! The fact that "one month ago" of some specific days in any month may result in the same month is nothing that I'd expect from a date implementation; in my book it's semantically counter-intuitive. - Thanks for pointing that out, it's good to know.
    – Janis
    Jun 5, 2015 at 7:13
3

Instead of relying on filenames for purging your backup files, you'd be safer relying on their time metadata.

For example you can delete all files older than 30 days with this command :

/usr/bin/find /path/to/your/files -type f -ctime +30 -delete

As a free bonus, running this everyday will allow you to keep your backup files on a rolling month, allowing a better disk space management.

For keeping 1st or 15th files, you could either store them in another directory, either update the find command with -not -name option.

0

You could try to see how the date works by the following:

date -d "$(date -d "Mar 31 2019" +%F) +1 month ago"
Sun Mar  3 00:00:00 EET 2019

So I think that based on the curent last month (not curent, if that is March), decreases the number of days from the last month from the curent month.

You could try the following syntax to delete files older then a number of days ( in the example bellow 31 days). One line to solve the problem (this is for a simple approach).

find /path/to/folder/with/arhives/ -mindepth 1 -mtime +31 -delete

For a more detailed approach you could also do something like this: 1. Finding the number of days for the curent month:

cal $(date +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}'
  1. Finding the number of days for the last month:

    echo "$(cal $(date +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}')-"$(cal $(date -d "+1 month ago" +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}') | bc

  2. So now we find the difference between those two months:

    echo "$(cal $(date +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}')-"$(cal $(date -d "+1 month ago" +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}') | bc

Now lets assign some variables to this 3 steps. Step 1 Variable Name: FCM Step 2 Variable Name: FLM Step 3 Variable NAme: DCL

FCM=$(cal $(date +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}')
FLM=$(al $(date -d "+1 month ago" +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}')
DCL=$(echo "$FCM-$FLM" | bc)

Verify if $DCL equals 0 (zero) and delete based on the difference between $FCM and $FLM:

if [ $DCL -ne 0 ]; then
    if [ $DCL -lt 0 ]; then
        find /path/to/folder/with/arhives/ -mindepth 1 -mtime +$(echo "$DCL+$FLM" | bc) -delete
    elif [ $DCL -gt 0 ]; then
        find /path/to/folder/with/arhives/ -mindepth 1 -mtime +$(echo "$DCL+$FLM" | bc) -delete
    fi
else
    find /path/to/folder/with/arhives/ -mindepth 1 -mtime +$FLM -delete
fi

You can also add a variable to "/path/to/folde/with/arhives/".

Conclusion: If you want to delete files older then one month (exactly), you need to adjust the exact number of days, if you are using "date" command and "+1 month ago".

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .