5

I need launch a few cron scripts on the last monday of every month.

I was wondering if combining ranges will do the job, e.g.:

8 04 19-26  *  2     $HOME/bin/mailstub

I hope I got it right and that my cron job will only run ONCE in the week between 19 and 26 of every month.

Would be happy to hear peoples comments,

I am using CentOS 5.6 - so the L construct mentioned in some places (e.g. Wikipedia) does not work on my system.

Thanks in advance,

Oz

1
  • The last monday can range between the 22th (when the 28th February is a Sunday) and the 31th day of the month, so this range is definitely wrong.
    – Sven
    May 3, 2011 at 15:54

4 Answers 4

3

That is setup to go multiple times per day. You want:

0 8 04 19-26 * * MON $HOME/bin/mailstub

That will go off at 8:04:00 on any day between the 19-26 that is on a Monday of any month of any year.

However, if it is Monday on the 19th, it is monday on the 26th. Therefore, you would want to have it from the 19-25

0 8 04 19-25 * * MON $HOME/bin/mailstub

So, this should go off once per month on a Monday. However, it is not guarenteed (or likely) to be the last Monday. If you need it to be the last and the L syntax does not work, you need to program the logic into the script being called. This is easily done with python but is beyond the scope of this question.

6
  • Thanks Stephen for your answer, the idea is that we have many scripts running monthly, but we realized that sometimes the run on the weekend, and than, we come on monday bombed with system emails. So, yeah, we could modify all the scripts - but i thought through cronjob it would be smarter...
    – oz123
    May 3, 2011 at 20:27
  • if monday is too close to the end of the month, we also don't have enough time to audit all the changes we need before the end of the month. Therefore, it is also fine if it the one before last monday, so I will accept you solution, instead of the above solution, which is complicated and does not work...
    – oz123
    May 3, 2011 at 20:41
  • 1
    For the record: dgrimbergens solution is correct, does indeed work and solves the problem as specified in the question.
    – Sven
    May 4, 2011 at 19:14
  • Check my answer for this kind of problems here. stackoverflow.com/questions/3241086/…
    – MGP
    Mar 31, 2014 at 15:07
  • 1
    Also, from man 8 crontab: The day of a command's execution can be specified by two fields — day of month, and day of week. If both fields are restricted (i.e., aren't *), the command will be run when either field matches the current time. So won't this also be run every Monday? Oct 10, 2016 at 10:33
10

Your cron job wil run on a Tuesday (5th field, day of week, 0 or 7 is Sunday), and not always the last Tuesday of the month. It would be better to use:

8 04 * * 1 [ $(date +"\%m") -ne $(date -d 7days +"\%m") ] && $HOME/bin/mailstub

This checks if the month today is not equal to the month 7 days from now. If not equal then it's the last monday of the month.

4
  • That's a good idea.
    – Sven
    May 3, 2011 at 15:55
  • I have put the date check in the script; putting it in the crontab is clever.
    – mpez0
    May 3, 2011 at 16:10
  • This is really not understood, and it does not work on my system. It gives me an error ... oz123@yenikaro:~$ date Mon May 30 22:45:13 CEST 2011 oz123@yenikaro:~$ $(date +"\%m") -ne $(date -d 7days +"\%m") && echo "yeah" \05: command not found
    – oz123
    May 3, 2011 at 20:38
  • 1
    It works in the crontab, you tried it on the commandline. If you put the following in your crontab, you can see it work (on 16:00 every day except the last 7 days of the month): 00 16 * * * [ $(date +"\%m") -eq $(date -d 7days +"\%m") ] && echo "it works" >> /tmp/crontab_result May 4, 2011 at 14:31
1

You can use the following:

For monday :

30 10 25-31 1,3,5,7,8,10 * test $(date +\%w) -eq 1 && cmd every Monday between the 25th and the 31st the months in 31 days at 10:30 am

30 10 24-30 4,6,9,11 * test $(date +\%w) -eq 1 && cmd every Monday between the 24th and the 30th month in 30 days at 10:30 am

30 10 22-29 2 * test $(date +\%w) -eq 1 && cmd every Monday between the 22nd and 29th of February at 10:30 am

For Wednesday:

30 10 25-31 1,3,5,7,8,10 * test $(date +\%w) -eq 3 && cmd every Wednesday between the 25th and the 31st the months in 31 days at 10:30 am

30 10 24-30 4,6,9,11 * test $(date +\%w) -eq 3 && cmd every Wednesday between the 24th and the 30th month in 30 days at 10:30 am

30 10 22-29 2 * test $(date +\%w) -eq 3 && cmd every Wednesday between the 22nd and 29th of February at 10:30 am

0

I also have faced this kind of scenario. Through cron, I was not able to run on the last Monday of every month. I did that through Python.

from datetime import datetime, timedelta
import os

today=datetime.today()
d7d=today+timedelta(days=7)

if today.month != d7d.month:
   os.system('sh /path to shell script')

cron tab entry looks like :

0 0 * * 1 /usr/bin/python3 /home/pythonfile.py

Here I am scheduling a Python file to execute every Monday but shell script gets executed on on only last Monday of the month.

Due to this logic : if today.month != d7d.month

Here I am adding seven days to the current date and checking if months are different.

For example : 20 jul is on Monday on this day .py that we scheduled through cron will be executed.

20 - jul  = monday
     +7 days
27 - jul  = monday 

Here months are compared. If the month is same logic written inside Python file will be ignored. The Python script will be executed next on 27-jul

27 - jul = monday
   +7 days
03 - Aug = monday

Now months are different so our code will be executed. The shell script inside it will be executed.

You must log in to answer this question.

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