3

I have seen this question which indicates that the relationship between the wday and mday fields of a CRON schedule is an OR relationship. Say for example I want to schedule something for every Friday the 13th.

Rather than the expected result, the CRON

0 0 13 * 5

will give me all Fridays of every month, as well as every 13th of every month.

Is there any way to avoid this behavior and specify an AND relationship? (There seems to be mention of older versions using an AND relationship, however I would prefer to use a single tool with the ability to do both)

3 Answers3

3

I guess, instead of specifying the wday (Friday=5), you'll just have to specify the months where the 13th is a Friday; so, for 2019:

0 0 13 9,12 * : do stuff, but avoid black cats

Or, eternally more elegant, create a small script:

$> cat /home/me/bin/test_friday_13
#!/bin/bash
if [ "$(date +'%A %d')" != "Friday 13" ]
then
    exit 1
else
    : do stuff, but avoid black cats
    exit 0
fi

and make the crontab entry:

0 0 13 * * /home/me/bin/test_friday_13

The script approach has the added benefit that you can run it from the command line. (Note: do not forget to alter the weekday name in the script to reflect your environment.)

  • The `9,12` method is risky. It's very likely the crontab won't be properly updated before March 2020 (the next month after 2019 that has a Friday the 13th). The wrapper script is good, and is a very common workaround for cron's limitations. – Keith Thompson Jul 12 '19 at 01:43
3

The cron-entry you are interested in is:

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
# |  |  |  |  |
# *  *  *  *  *   command to be executed
  0  0 13  *  *   [ $(date "+\%u") = "5" ] && command

This will execute the cronjob every 13th of the month. It will compute the day of the week, and test it if it is a Friday (5). If so, it will execute command.


Extended explanation: If you want to have special conditions, you generally need to implement the conditions yourself with a test. Below you see the general structure:

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
# |  |  |  |  |
# *  *  *  *  *   command to be executed
  0  0 13  *  *   /path/to/testcmd && command

The command testcmd generally returns exit code 0 if the test is successful or 1 if it fails. If testcmd is successful, it executes command. A few examples that use similar tricks are in the following posts:

The test you want to perform is written in /bin/sh as:

[ $(date "+%u") = 5 ]

Which makes use of the test command (see man test). This is POSIX compliant and will work with any shell that your cron might run in (sh,bash,dash,ksh,zsh). The command date "+%u" returns the weekday from 1 to 7 (Sunday is 7). See man date for more info.

So your cronjob would look like:

  0  0 13  *  *    [ $(date "+\%u") = 5 ] && command

Note that we have to escape the <percent>-character.

A % character in the command, unless escaped with a backslash (\), will be changed into newline characters, and all data after the first % will be sent to the command as standard input.

source: man 5 crontab

Community
  • 1
  • 1
kvantour
  • 25,269
  • 4
  • 47
  • 72
0

Unfortunately, CRON doesn't work the way you want

You can see all available options on below url

https://www.freeformatter.com/cron-expression-generator-quartz.html

So what you can do is the execute the cron on every 13th of the month but don't let the command run when its Friday

0 0 0 13 * ? * mybatchjob.sh

mybatchjob.sh

if [ `date +'%A'` = "Friday" ]; then 
   echo "Yep its Friday"; 
else 
   echo "Not Friday"; 
fi

This will make sure that the intended program only runs on Friday and the 13th

Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • 1
    Be advised that the output of this command depends on the `locale` of your system. `$ LC_ALL=is_IS.utf8 date '+%A'` returns `föstudagur` for a Friday. – kvantour Jul 19 '19 at 14:04