It is often useful to schedule tasks (i.e. jobs, processes) to occur at regular intervals. Perhaps you need to backup a database every night, pull the latest updates from a popular git repository, sync data between multiple systems, or punch a time-clock. Maybe you need to let your colleagues know you’ve got a hangover, or you have a coffee addiction. On *nix systems, anything you can run from the command line can be scheduled with cron.
A crontab (short for “cron table”) file stores the information required to execute scheduled jobs. On Mac OS, crontab files are located at /var/at/tabs, however these files should rarely be edited directly—instead the crontab command line utility should be used to interact with these files.
# ┌───────── Minute (0-59)
# │ ┌─────── Hour (0-23)
# │ │ ┌───── Day (1-31)
# │ │ │ ┌─── Month (1-12)
# │ │ │ │ ┌─ Weekday (0-7) (Sunday=0||7)
> * * * * * Command_to_execute
- The asterisk (
*) operator specifies all possible values for a field, e.g. every hour or every day. - The comma (
,) operator specifies a list of values, e.g.1,3,4,7,8. - The dash (
-) operator specifies a range of values, e.g.1-6is equivalent to1,2,3,4,5,6. - The slash (
/) operator specifies stepped values, e.g.*/3in the hour field is equivalent to0,3,6,9,12,15,18,21.
| Field | Value | Description |
|---|---|---|
minute |
0-59 |
The exact minute that the command sequence executes |
hour |
0-23 |
The hour of the day that the command sequence executes |
day |
1-31 |
The day of the month that the command sequence executes |
month |
1-12 |
The month of the year that the command sequence executes |
weekday |
0-6 |
The day of the week that the command sequence executes (Sunday=0, Monday=1, Tuesday=2…) |
command |
special | The complete sequence of commands to execute. The command string must conform to Bourne shell syntax. Commands, executables (such as scripts), or combinations are acceptable. |
| Shorthand | Description | Equivalent |
|---|---|---|
@reboot |
Runs at startup and when the cron daemon is restarted | |
@hourly |
Runs once an hour | 0 * * * * |
@daily |
Runs every day at midnight | 0 0 * * * |
@midnight |
Runs every day at midnight | @daily |
@weekly |
Runs every Sunday at midnight | 0 0 * * 0 |
@monthly |
Runs on the first day of each month at midnight | 0 0 1 * * |
@yearly |
Runs on January 1 at midnight | 0 0 1 1 * |
@annually |
Runs on January 1 at midnight | @yearly |
Tip: The command can optionally be prefixed by @AppleNotOnBattery' to tell cron` not to run the command when functioning on battery power.
Examples
cron_entry='0 */6 * * * /usr/local/bin/brew update &>/dev/null'
if ! crontab -l | fgrep "$cron_entry" >/dev/null; then
(crontab -l 2>/dev/null; echo "$cron_entry") | \
crontab -
fi
# Schedule Google Fonts Updates
read -d '' cron_entry <<-CRON
0 */6 * * * sh -c 'cd "${GOOGLE_FONTS_DIR}" && git fetch -fp --depth 1 && \
git reset --hard @{upstream} && git clean -dfx' &>/dev/null
CRON
if ! crontab -l | fgrep "$cron_entry" >/dev/null; then
(crontab -l 2>/dev/null; echo "$cron_entry") | \
crontab -
fi
Note: This and other cool command line tools can be found on my github project, starter.
# Running SSL renewal twice per day - at a random minute within the hour
# (it won't do anything until certificates are due for renewal or revoked,
# but running it regularly would give your site a chance of staying online
# in case a revocation occured.
8 */12 * * * /usr/bin/certbot renew --quiet --post-hook "/usr/local/apache2/bin/apachectl graceful"
Tips
Because cron is a non-interactive shell, run by root.
Change the shell used by cron with:
# Use /bin/bash, instead of /bin/sh (default)
SHELL=/bin/bash
# Set the PATH variable to locate commands
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
or
BASH_ENV="/root/.bashrc"
# Disable mail
MAILTO=""
A Better Way
Apple’s documentation on launchd makes reference to cron.
Note: Although it is still supported,
cronis not a recommended solution. It has been deprecated in favor oflaunchd.… Because installing
cronjobs requires modifying a shared resource (thecrontabfile), you should not programmatically add acronjob.
https://ole.michelsen.dk/blog/schedule-jobs-with-crontab-on-mac-osx.html https://alvinalexander.com/mac-os-x/mac-osx-startup-crontab-launchd-jobs http://www.adminschoice.com/crontab-quick-reference https://www.schiff.io/blog/2017/08/31/automating-slack-status-launchd