Cron job every Friday except 4th

Hi,

I'm looking for a way to run a backup in the cron every Friday, except every 4th Friday (as we do monthly backups then).

The monthly backups are not the 4th Friday of each month, but every 4th Friday (i.e. we don't want this backup to run on x Friday, then the Friday 4weeks/28days later).

This backup also runs Monday-Thursday getting called normally from the cron, but currently it is run manually on Fridays due to this. I understand we will need another script with validation, and call the normal backup script, then put that in the cron - but unsure how to do it.

Thanks in advance!
Rab

I think the best will be to implement it in the script to check if the day is not the 4'th friday of the month.

Thanks for the reply, although it may not necessarily be the 4th Friday we do our monthly backups. It's every 4 weeks. A good example of this would be in April 2011. Our monthly backups would be on Friday 1st April, and Friday 29th April.

Cheers,
Rab

Maybe you can use this in a script calling the backup procedure

OFFSET=0 # put any value between 0 and 3 to fix the date of the monthly backup
if (( ( $(date +%U | sed 's/^[0]*//') + OFFSET ) % 4 )) # spaces just for better readability
then
    # weekly backup
else
    # monthly backup
fi

You can add a test to your script like:

if [ $(date +%d) -lt 22 -a $(date +%u) -eq 5 ];then echo OK;else exit;fi

Thanks - would it be possible to break it down as to what it does?

Cheers,
Rab

One improvement to speed up :wink:

if [  $(date +%u) -eq 5 -a $(date +%d) -lt 22 ];then echo OK;else exit;fi

Reference : Man Page for date (All Section 1) - The UNIX and Linux Forums

  • $(date +%u) -eq 5 If week day is 5 (Friday), I put this test first like that we will not try the second test(call date) if the first one is false.
  • -a and
  • $(date +%d) -lt 22 monthly day number less that 22(the script should run in the first 3 weeks/21 days)
  • then echo OK Do something , run your script, etc
  • else exit if one or both condition not true.

Thanks! Although a monthly backup may take place on say the 1st. It's not necessarily the last Friday of the month. I'm not really sure how I can write this down clearly. There is an example in post 3 ^

If I understand your code that will run it the first, second and third Friday, but not the fourth of each month, whereas we require it to run on every fourth week.

I was thinking along the lines of using an initial date, then +28 days (multiple). Since there is no set date as such the monthly backups take place, its every four weeks. So we could start the cycle in the script on whatever date. For example, I know our next monthly backups begin on Friday 30th April 2010. Here is a few dates after this to try and give more of an idea of the cycle -

30th April (Just happens to be the last Friday)
28th May (Just happens to be the last Friday)
25th June (Just happens to be the last Friday)
23rd July (Not the last Friday, it's in fact the 4th out of 5 Fridays in July)
20th August (Not the last Friday either, it's the 3rd out of 4)

The reason it is set a little odd like this is because it's the weekend after our pay (we get paid 4 weekly, not monthly).

Hope this makes sense.

Thanks for the replies!
Rab

Edit - Poor attempt at pseudo like code below

Cron Entry - 00 21 * * 5 /backupscript

backupscript -

if todays date is +28 (multiple) 30th April 
then run monthly backup
else run normal backup
fi

There is probably a better way to do it, I don't know enough about scripting to get my head around it :slight_smile:

Edit 2 - This is AIX v5.3 if it makes any difference.

Any solution will need to know when the last monthly backup ran or when the next monthly backup is scheduled to run, perhaps by having that info stored in a file by the monthly backup process. With that info in hand, it should be easy enough for the daily to decide if it should run on any given friday.

Regards,
Alister

Good point.

Perhaps adding into the monthly backup script a touch command to create a file with todays date +28 days.

Then on the call script in the cron check to see if that date matches todays date? Would this work?

I'm not so sure on the syntax for this though, or if it is possible (I imagine it is though).

Thanks!
Rab

You want to to run a weekly backup script every week except every fourth week of the year when you want to run a different script/command.
What about :wink:

if [ $(date +%u) -eq 5 -a $((($(date +%j) / 7) % 4)) -gt 0 ];then echo fourth week ;else echo regular week;fi

Edit:
Let's explain :

  • text $(date +%u) -eq 5
    if 5th day of the week(Friday) move to next condition.
  • text $((($(date +%j) / 7) % 4)) -gt 0

    calculate the week number from the beginning of the year.
  • text $((($(date +%j) / 7) % 4)) -gt 0

    divide the result by 4 and get the reminder, if the reminder is 0 the week is a fourth week.

If you run my code tomorrow (April 23, 2010) will be a fourth week Friday :wink:

I'll give it a try with some overly commented code.
Oh. And run it as a cron job every friday.

#!/bin/bash

# name of file to keep track of last backup
lastbackup=./lastbackup

if [ -f $lastbackup ]
then

# Time of last backup (seconds since epoch)
    timelast=$(stat -c %Y $lastbackup)

# Current time (seconds since epoch)
    timenow=$(date +%s)

# 86400 sec per day. 28 days is four weeks
    fourweeks=$(( 86400 * 28 ))

# slacktime = Some slack so we survive bad clock
# and daylight saving time. (2h)
    slacktime=$(( 3600 * 2 ))

# Have more than four weeks passed? (minus 2h)
    timepassed=$(( $timenow - $timelast ))
    fourweeksslack=$(( $fourweeks - $slacktime))

    if [ $timepassed -gt $fourweeksslack ]
    then
        echo BackupBackupBackup
    else
        echo NoBackup
    fi
else
# Should only occur first time script is run
    echo $lastbackup was created
    touch $lastbackup
fi

The logic of the test command does not agree with the echo statements. It will echo "fourth week" 3 out of 4 fridays.

Instead of "-gt 0", "-eq 3" should harmonize with the echo statements.

Regards,
Alister

[/list]
You can use the +%U format which gives the week number (as i posted above).

(( $(date +%U) % 4)) 

will return false 1/4 and true 3/4

Cheers for the replies.

I have a few test things set up in the cron of a test UNIX box to see how they go, executing writing to files rather than running any backups.

Will see over the next few weeks. No rush to implement this in live environment.

Cheers,
Rab

Not exactly :wink: 21 will be on the fourth and 28 on the fifth.
I think this will do the job:

var=$(date +%j)
if [ $(date +%u) -eq 5 ] && [ $((($var / 7) % 4))$(($var%7)) -gt 30 -o $((($var / 7) % 4))$(($var%7)) -eq 0 ];then echo fourth week ;else echo regular week;fi

Yep but will start on Sunday :wink:

Hi again!

Still trying to get this to work, I have let it run for a while now and here is the results:

Code being run every Friday:

var=$(date +%j)

if [ $(date +%u) -eq 5 ] && [ $((($var / 7) % 4))$(($var%7)) -gt 30 -o $((($var
/ 7) % 4))$(($var%7)) -eq 0 ];

then echo Monthly Backup Ran >> /rab/testing.txt ;

else echo Weekly Backup Ran >> /rab/testing.txt;

fi

Output from testing.txt (note - I have manually added lines to this to keep track of dates):

Here you can see that the script is running once every 4 weeks, but it just falls on the wrong date.

So I'm guessing I need to offset the remainder it looks for (-eq 0) to something else? To offset it by 2 weeks. As it is out of sync by 2 weeks.

Tonight is a "Monthly backup" week(end).

Any ideas?
Cheers,
Rab