Run a perl or shell script cron job on the first Monday or the Nth weekday of the month

Posted on in Categories Howto, Linux, Shell scripting, Sys admin, Tips, UNIX last updated July 5, 2007

This is a classic problem. One of our FAQ is about cron job. I received lots of email with a question:

How do I run my script on 3rd Monday or 4th Friday only?

Cron does not offer this kind of facility i.e. you cannot run a script on the Nth weekday of the month.

However with one shell liner you can force to run a script on a given day:

Consider following date command, it will print day:
$ date +%a
Output:

Thu

You can compare output with weekday name using bash test [exrp ] syntax and the control operators && (AND list), you can write:
$ [ $(date '+%a') == 'Thu' ] && echo 'Today is Thu, run a command' || echo 'Noop'

First echo command get exectued only on Thursday. Now all you have to do is write a cron job to execute on first Monday:
# crontab -e
Now append code as follows:
# Run a script called myscript.sh on First Monday at 11:30:
30 11 1-7 * Mon [ "$(date '+%a')" == "Mon" ] && /path/to/myscript.sh

Hope this small tip will save your day. Please do share some of your favorite bash / shell scripting hacks in the comments. I will highlight some of the best in next shell scripting post.

See also:

17 comment

  1. Nice trick, but the crontab is incorrect. As written it will run on all mondays. See crontab(5): “Note: The day of a command’s execution…”

    # Run a script called myscript.sh on First Monday at 11:30:
    30 11 1-7 * * [ “$(date ‘+%a’)” == “Mon” ] && /path/to/myscript.sh

    1. Hi, I wanted to run a script first Thursday of the every month. I added the script in crontab as per your suggesition. It seems somehow it didn’t work.
      syntax:

      32 13 1-7 * * [“$(date ‘+%a’)” == “Thu”]&&/warehouse/db2scripts/db2_test.ksh > /tmp/db2_test.del

      Can you please let me know if i did anything wrong.

      Regards,
      Ram.

  2. Hi,
    I need to execute a script file with the crontab.
    I just enter the entry in cronfile and it is not working…
    But I can exectute the script manually from the same location with out any issues…

    Please advice on this
    # Minute Hour Day of Month Month of Year Day of Week Command
    57 * * * * sudo /var/opt/R_5.0.0/WebNMS/mysql/bin/mysqlbackup.sh

  3. Just to share few lines regarding the problem I faced while setting up shell script thru cron …
    Make sure you set at the very top of your script the directory path where you script lies, or else your script will crash using the relative path …
    use …
    cd `dirname $0`
    This will take cron to your scripts directory and execute it form there ..hope it will save some1s time.

  4. Whoever put comment #4 it saved me a lot of time, I had a problem running the script in cron, but it did it!

    Thanks a lot for your help.

  5. I should have read the responses. Post 1 is right. I set this up and discovered the same thing.

    Thanks for the tip anyway though it certainly helped me.

  6. Hi ,
    I don’t understanding why my perl script is not executing through crontab .
    but it runs properly if we run it at command prompt by typing “perl $path_of_script”.
    I found that cron daemon reads the line “perl $path_of_script” as command at proper timing defined in crontab and logs it in /var/log/cron.
    But it is not executing.
    I think it may be issue of environmental variables for cron daemon.
    How to debug this issue ?
    Thanks for help in advance.

  7. Note that you must escape (\) the % in a crontab entry, otherwise cron will treat the % as a newline and feed the rest of the command line as STDIN. The correct command would be:
    30 11 1-7 * * [ “$(date ‘+\%a’)” == “Mon” ] && /path/to/myscript.sh

    Thanks for the great tip

  8. I had to use the escape as Brian noted. I also had to use a single ‘=’ for the test. I could use ‘==’ but the job would error out if I had any spaces around the ‘==’.

    These worked for me on Debian 6.0.7:

    0 9 29-31 * * [ “$(date ‘+\%a’)”==”Wed” ] && echo “today is the fifth Wednesday” > ~/isWed || echo “today is not the fifth Wednesday” > ~/isWed

    0 9 29-31 * * [ “$(date ‘+\%a’)” = “Tue” ] && echo “today is the fifth tuesday” > ~/isTues || echo “today is not the fifth Tuesday” > ~/isTues

    ymmv

  9. Just found this by accidentally clicking a wrong link, and I have to say this article is wrong.

    Cron has a perfectly good way to check the weekday, it’s the last date based param:

    Min Hour Date Month DoW Username Command

    To run something on the first Monday of every month use:

    0 0 1-7 * 1 root command

    To run on the second thursday you can use:

    0 0 8-15 * 4 root command

    To run every sunday:

    0 0 * * 0 root command

    To run every second wednesday:

    0 0 */2 * 3 root command

  10. @Liam: It’s you who are incorrect. When specifying both DoM and DoW, the command will be run if EITHER of them matches, so:
    0 0 1-7 * 1 root command
    will run every day on days 1-7, and ALSO on day 1 of the month.

    Please see the crontab(5) man page (man 5 crontab).

  11. Hi All,

    I need to run cronjob first 3 mondays .I ran below cron it is running daily.My operating system is Redhot linux 6.7.

    cron :
    00 11 1-25 * 1 sh /home/db2inst/test.sh

    Can you please help me any body.

    Regards,
    Kumar

Leave a Comment