31

I'd like to run a job from cron at 8.30 on the first Monday of every month. The cron Wikipedia page says

While normally the job is executed when the time/date specification fields all match the current time and date, there is one exception: if both "day of month" and "day of week" are restricted (not "*"), then either the "day of month" field (3) or the "day of week" field (5) must match the current day.

(my emphasis)

Does that mean I can't do the first Monday of the month, I can only do the first (or whatever) day of the month? I can't think of a way round it.

  • slhck - that sounds like a good solution - would you mind expanding it into an answer with the full code? then i'll mark it as correct :) – Max Williams May 28 '12 at 8:51

12 Answers 12

39

You can put the condition into the actual crontab command:

[ "$(date '+%a')" = "Mon" ] && echo "It's Monday"

Now, if this condition is true on one of the first seven days in a month, you have its first Monday. Note that in the crontab, the percent-syntax needs to be escaped though:

0   12  1-7 *   *   [ "$(date '+\%a')" = "Mon" ] && echo "It's Monday"

Replace the echo command with the actual command you want to run. I found a similar approach too.

  • actually, slhck, i spoke too soon - this isn't working in my crontab: it seems to have a problem with the date test for some reason. This works in the command line [ "$(date '+%a')" = "Mon" ] && echo "It's Monday" as does [ $(date '+%a') = "Mon" ] && echo "It's Monday" But, in the crontab it seems to be failing at this test. I can't get at any useful feedback from cron either: i'm trying this [ "$(date '+%a')" = "Tue" ] >> /home/deploy/cron.log 2>&1 to capture any error output into a log but that's not working either :/ – Max Williams May 29 '12 at 8:53
  • Hm. Can you check whether the date output is correct? For example, just let a cron command run that outputs this to a file: date '+%a' > ~/datetest 2>&1 – then check if that resulted in the right string to compare against. – slhck May 29 '12 at 8:58
  • 1
    I found the problem - the percent in +%a needed escaping when it was in the crontab, ie the line needed to be this: [ "$(date '+\%a')" = "Mon" ] && echo "It's Monday". If you could update your answer with that it would be helpful to future readers :) Thanks again - max – Max Williams May 29 '12 at 9:33
  • Oh, now I see why. Glad it works now, thanks for trying it out! – slhck May 29 '12 at 9:35
13

I have a computer with locale on Spanish, so, this approach isn't working for me because mon changes to lun

Other languages would fail as well, so, I did a slight variation on the accepted answer that takes out the language barrier:

 0 9 1-7 * *   [ "$(date '+\%u')" = "1" ] && echo "¡Es lunes!"
  • +1 ¡Muy bien, señor! – JakeGould Oct 25 '18 at 0:03
  • 1
    Gracias ¡Pura vida! ;D – cumanacr Oct 25 '18 at 0:10
  • This should be the accepted answer. I have a Dutch locale which also uses different names for weekdays. And using numbers also feels cleaner than comparing strings to determine the day of the week. – 0ne_Up Nov 28 '18 at 10:54
7

I find it easier when there's no need to handle day numbers.

Run First Monday of month:

0 2 * * 1 [ `date '+\%m'` == `date '+\%m' -d "1 week ago"` ] || /path/to/command

i.e. if the month 1 week ago is not the same as the current month then we are on the 1st day 1 (= Monday) of the month.

Similarly, for the Third Friday

0 2 * * 6 [ `date '+\%m'` == `date '+\%m' -d "3 weeks ago"` ] || /path/to/command

i.e. if the month 3 weeks ago is different to current month then we are on the 3rd day 6 (= Friday) of the month

  • Day 6 of week is Saturday not Friday. – Robert Jun 5 at 9:23
4

I have scheduled a job to run on the 4th Monday of every month at 4:00 PM as follows:

0 16 22-28 * Mon [ "$(date '+\%a')" == "Mon" ] && touch /home/me/FourthMonOfMonth.txt
1

As far as I know it is NOT possible using only crontab, however one can use a wrapper function to pick the correct day from a "first seven days of month" contab entry; see this from entry.

The wrapper script would be

#! /usr/bin/ksh
day=$(date +%d)
if ((day <= 7)) ; then
   exec somecommand
fi
exit 1

and you would need to run it (assuming it is called wrapper.sh and globally available) using the crontab entry

0 0 * * 1 wrapper.sh
  • thanks elemaki. I thought about a similar solution using some extra code inside the task that gets run, getting it to test whether it's the first monday of the month inside the script, and then calling it every monday in crontab. It's a ruby script so it's easy to test the day of th week. But i was hoping there'd be a crontab only way. – Max Williams May 25 '12 at 15:56
1

On Solaris 10 I had to format the condition as follows:

[ `date +\%a` = "Sat" ] && echo "It's Saturday"
1

You can try running cronjob for first seven days of month and let it execute only on Monday.

30 8 * * 1 [`date +\%d` -le 07] && <job>

Above should work for you.

  • +1 more success hit ration then to run for the first week and check for Monday. :-) – xmedeko Mar 22 '17 at 7:28
1

I recommend to use

"$(/bin/date '+%\w')" = "1"

instead of

"$(date '+\%a')" = "Mon"

to avoid locale problem.

0

I made a general solution for this kind of problems, it works for first, second, third..... last weekday of the month.

You can use it like this:

30 06 * * Mon run-if-today 1 "Mon" && echo "First Monday"
30 06 * * Thu run-if-today 3 "Thu" && echo "Third Thursday"
30 06 * * Sun run-if-today L "Sun" && echo "Last Sunday"

The script run-if-today check for both the weekday and the desired week date range, if both match then it returns 0, otherwise 1.

Check the code here. https://github.com/xr09/cron-last-sunday

0

I believe this solves the problem more elegantly:

30 8 1-7 * 1 /run/your/job.sh
  • Doh! : "If both fields are restricted (ie, aren't *), the command will be run when either field matches the current time." – symcbean Jul 10 '14 at 8:35
  • Also on February (the one that ends 28th) it will not be run every 4 years. – igraczech Oct 5 '16 at 11:00
  • "either" means any of them, not "both". this will run every day for the 1st 7 days of the month. – minusf Aug 30 '18 at 14:42
  • This row would run a command on the first to seventh of each month, as well as on every Monday – Tomasz Jakub Rup Nov 30 '18 at 5:23
0

Since I interpret my cron statements using php and js, I can't use bash. Finally I found that it is in fact possible with just cron:

0 30 8 * 1/1 MON#1

Hope this helps someone else. Regardless, I wish you all a beautiful day. :-)

-1
0 9 1-7 * 1 * 

This will work for every monday of every month.

  • An answer has been accepted, is your answer better, different or useful on a newer version, etc. – mic84 Sep 4 '18 at 9:32

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.