25

I want a script to run every 40mins beginning on the 40th minute.
so that means:

00:40, 01:20, 02:00, 02:40, 03:20...

So I made this entry to cron:

*/40 * * * * /path/to/script/foo.sh

Unfortunately this runs the script every 40th minute of the hour:

00:40, 01:40, 02:40...

The same goes with the script that I meant to run every 25mins.

Am I missing something here?


ANSWERS
Alright, in case you happen to drop by here having the same problem
here's how I solved it:

# 40mins-interval
40 0 * * * /path/foo.sh         (0)
0,40 2-22/2 * * * /path/foo.sh  (2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
20 1-23/2 * * * /path/foo.sh    (1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23)  


# 25mins-interval
25,50 0 * * * /path/foo.sh              (0)
0,25,50 5-20/5 * * * /path/foo.sh       (5, 10, 15, 20)
15,40 1-21/5 * * * /path/foo.sh         (1, 6, 11, 16, 21)
5,30,55 2-22/5 * * * /path/foo.sh       (2, 7, 12, 17, 22)
20,45 3-23/5 * * * /path/foo.sh         (3, 8, 13, 18, 23)
10,35 4-19/5 * * * /path/foo.sh         (4, 9, 14, 19)

Notes:
1. There will still be collisions in this schedule (i.e: see schedules that run on the 0th and 10th minutes on both intervals).
2. The script won't run at an exact interval from its last run today going on the next day (i.e: 25min interval ends @23:45 today, begins @00:25 next day).

cr8ivecodesmith
  • 2,021
  • 5
  • 21
  • 30
  • 1
    read this: http://stackoverflow.com/questions/745901/how-to-do-a-cron-job-every-72-minutes – Book Of Zeus Nov 18 '11 at 11:59
  • 1
    Thanks! This sucks but I guess I'll have to do the 'manual' setting of the intervals as a dirty fix for now. – cr8ivecodesmith Nov 18 '11 at 12:06
  • 1
    I know it's been 4 years, but I may have a solution to the 25 minute cron. You could have the cron run every minute (or every 5 minutes..) and your script would detect if 25 minutes has passed. If that's true, then your script would do its job. – Kayla Jan 04 '15 at 19:02
  • 1
    On the 40-minute interval, why would you skip 00:00? The cron will run at 23:20 and 00:40, so you're skipping an interval there. – paulwal222 Jun 16 '20 at 16:06

5 Answers5

20

It always splits the current hour only.

40/40 = 1 so it runs every 40th minute of an hour.

*/5 would do 5, 10, 15...

You should go for larger intervals.

Do */30 for your 25 minute interval and every 60 minutes for your 40 minutes interval.

Otherwise set up two crontabs for your script:

0,40 */2 * * * /path/to/script/foo.sh
20 1,3,5,7,9,11,13,15,17,19,21,23 * * * /path/to/script/foo.sh
R6D1H2
  • 47
  • 2
  • 10
Udo Held
  • 12,314
  • 11
  • 67
  • 93
13

For the task you want to accomplish you have to write a little bit more complex entry in your crontab.

You see the pattern above?

00:40, 01:20, 02:00, 02:40, 03:20 and again 04:00, 04:40, 05:20, 06:00, 06:40, 07:20, 08:00

I can break it down into three entries:

  1. Every even hour you have to run it at 40th min
  2. Every odd hour you have to run it at 20th min
  3. Every even hour you have to run it on 0. (Except 0 hour)

You can accomplish this with more than one entries:

#1
*/40 0,*/2 * * * /path/to/script/foo.sh
#2
*/20 1,*/2 * * * /path/to/script/foo.sh
#3
0 2,*/2 * * * /path/to/script/foo.sh

NOTE: It might have minor issues, but there I gave you direction :)

PS: This will explain alot more

DivinesLight
  • 2,398
  • 2
  • 24
  • 30
5

You can achieve any frequency if you count the minutes(, hours, days, or weeks) since Epoch, add a condition to the top of your script, and set the script to run every minute on your crontab:

#!/bin/bash

minutesSinceEpoch=$(($(date +'%s / 60')))

# every 40 minutes
if [[ $(($minutesSinceEpoch % 40)) -ne 0 ]]; then
    exit 0
fi

date(1) returns current date, we format it as seconds since Epoch (%s) and then we do basic maths:

# .---------------------- bash command substitution
# |.--------------------- bash arithmetic expansion
# || .------------------- bash command substitution
# || |  .---------------- date command
# || |  |   .------------ FORMAT argument
# || |  |   |      .----- formula to calculate minutes/hours/days/etc is included into the format string passed to date command
# || |  |   |      |
# ** *  *   *      * 
  $(($(date +'%s / 60')))
# * *  ---------------
# | |        | 
# | |        ·----------- date should result in something like "1438390397 / 60"
# | ·-------------------- it gets evaluated as an expression. (the maths)
# ·---------------------- and we can store it

And you may use this approach with hourly, daily, or monthly cron jobs:

#!/bin/bash
# We can get the

minutes=$(($(date +'%s / 60')))
hours=$(($(date +'%s / 60 / 60')))
days=$(($(date +'%s / 60 / 60 / 24')))
weeks=$(($(date +'%s / 60 / 60 / 24 / 7')))

# or even

moons=$(($(date +'%s / 60 / 60 / 24 / 656')))

# passed since Epoch and define a frequency
# let's say, every 7 hours

if [[ $(($hours % 7)) -ne 0 ]]; then
    exit 0
fi

# and your actual script starts here
stefanmaric
  • 271
  • 4
  • 4
  • 1
    An interesting approach, and I like the shell code. Strictly speaking though, this does not answer the question _How do set cron to run my script every 40mins/25mins?_ since it requires that cron run the script every minute. – CODE-REaD Feb 05 '20 at 18:18
  • Indeed, not technically correct, it is a workaround. To clarify, I initially came up with this to workaround constrained environments, specifically, OpenShift pre v3, which API to create cron jobs was placing the actual script files inside folders named after the frequency, like ".openshift/cron/minutely/". – stefanmaric Feb 06 '20 at 11:35
5

You will need to add several entries for the same script to cron, one for running on the hour, one for twenty past and one for twenty to the hour.

0 0,2,4,6,8,10,12,14,16,18,20,22 * * * script
20 1,3,5,7,9,11,13,15,17,19,21,23 * * * script
40 0,2,4,6,8,10,12,14,16,18,20,22 * * * script

You say that it should start at 00:40, but the run of the previous day will be at 23:20. Do you want an 80 minute gap in runs around midnight?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
Andrew Wilkinson
  • 10,682
  • 3
  • 35
  • 38
0
#! /bin/sh

# Minute Cron
# Usage: cron-min start
# Copyright 2014 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution

# Run this script under Cron once a minute

basedir=/etc/cron-min

if [ $# -gt 0 ]
then
   echo
   echo "cron-min by Marc Perkel"
   echo
   echo "This program is used to run all programs in a directory in parallel every X minutes."
   echo
   echo "Usage: cron-min"
   echo
   echo "The scheduling is done by creating directories with the number of minutes as part of the"
   echo "directory name. The minutes do not have to evenly divide into 60 or be less than 60."
   echo
   echo "Examples:"
   echo "  /etc/cron-min/1      # Executes everything in that directory every 1  minute"
   echo "  /etc/cron-min/5      # Executes everything in that directory every 5  minutes"
   echo "  /etc/cron-min/13     # Executes everything in that directory every 13 minutes"
   echo "  /etc/cron-min/75     # Executes everything in that directory every 75 minutes"
   echo
   exit
fi

for dir in $basedir/* ; do
   minutes=${dir##*/}
   if [ $(( ($(date +%s) / 60) % $minutes )) -eq 0 ]
   then
      for program in $basedir/$minutes/* ; do
     if [ -x $program ]
     then
        $program &> /dev/null &
     fi
      done
   fi
done