cron is one of those tools better shown than explained. This quick guide does just that. It only covers Vixie’s cron, the flavor present in most Unix nowadays, such as Linux and BSD (that includes the mac). I only show stuff that I find most useful. At the end of this document I list some gotchas that may help you resolve some issues. To dig deeper, `man 5 crontab` is what you want.
==================================================================
Basic usage
cron jobs are set in a crontab file. From the shell prompt:
Edit crontab
$ crontab -e
List cron jobs
$ crontab -l
Remove crontab
$ crontab -r
==================================================================
crontab file usage
* * * * * command - - - - - | | | | | | | | | +----- day of week (0 - 6) (Sunday=0) | | | +-------- month (1 - 12) | | +----------- day of month (1 - 31) | +-------------- hour (0 - 23) +----------------- min (0 - 59)
- a single value: 1
- a range of values: 1-5
- all values: *
- a list of values: 3,5,8
- a repeat patterns: 2/3 (see examples for explanation)
- if both dom and dow are specified they will be executed on their respective schedule
- months and days of the week can be specified by name
- some special convenient strings you can use as shortcuts
String || Equivalent ------------------------------------------ @yearly || 0 0 1 1 * @annually || 0 0 1 1 * @monthly || 0 0 1 * * @weekly || 0 0 * * 0 @daily || 0 0 * * * @midnight || 0 0 * * * @hourly || 0 * * * * @reboot || Run once, at startup. ------------------------------------------
==================================================================
Examples of cron schedules
each min
* * * * *
each hour
0 * * * *
each hour, after 5 min
5 * * * *
every day at 4:35pm
35 16 * * *
the 1st of each month at midnight
0 0 1 * *
the 1st and 15th of each month at noon
0 12 1,15 * *
every hour, on the 1st of april
0 * 1 4 *
the 25th of december at midnight (i.e going from 24th to 25th)
0 0 25 12 *
every fridays at 5pm
0 17 * * 5
every thursdays at 5pm, only in august
0 17 * aug thur
at 9am, noon and 5pm, from monday to friday
0 9,12,17 * * 1-5
thursday every two weeks at 6am (i.e. every 2 times it hits the 4th day of the week)
0 6 * * 4/2
every 5 minutes (i.e. every 5 times it hits a minute, from the start of the job)
*/5 * * * *
at 6am every 10 days (i.e. every 10 times it reaches 6am)
0 6/10 * * *
at reboot
@reboot /home/mike/my_ini_script.sh
==================================================================
last day of the month
cron doesn’t have any native facility to get the LDOTM. With a bit of logic though, and some basic shell tools, we can achieve this. Today being the last day of the month implies a number of facts you can use to implement an algorithm.
- tomorrow’s the 1st day of some month
- tomorrow’s month is different from today’s
- tomorrow’s day of the month is less than today’s
Lets implement the first algorithm using the `date` tool, available on most GNU systems. If your version of `date` isn’t able to do these operations, look for some alternatives scripts to help you with the task. Popular options are scripts combining `cal`, `sed` and `awk`. But I think most people should be fine with this:
Cron job running on the last day of the month:
0 0 28-31 * * [ `date --date=tomorrow +\%d` -eq '01' ] && our_command
Explanation:
I set the job to attempt the command only from the 28th to the 31st each month. This is a useless extra step, purely for aesthetical purpose. With today’s processing power, it’s equivalent to removing a handfull of toothpicks from a cargo ship.
0 0 28-31 * *
getting the date:
`date` ^----^ | these are backticks, not single quotes
tomorrow’s date:
`date --date=tomorrow`
just the day number:
`date --date=tomorrow +%d`
lets escape the percent symbol for use within crontab (see gotchas):
`date --date=tomorrow +\%d`
comparing that number to ‘01′:
[ `date --date=tomorrow +\%d` -eq '01' ]
^------------------------------------^
|
spaces here are required
if the previous expression evaluates to true then boolean logic allows us to try to evaluate the next expression, which is where we put the command.
[ `date --date=tomorrow +\%d` -eq '01' ] && our_command
------------------------------------ -- -----------
| | |
if true then command
==================================================================
cron permissions
2 lists to control permissions, with simply 1 username per line.
/etc/cron.allow
/etc/cron.deny
cron permissions for all users based on allow/deny list existence.
| allow exists | allow not exists | -------------+--------------+--------------------| deny exists | allow only | all except deny⚐ | -------------+----------+------------------------| deny !exists | allow only | system dependant⚑ | -------------+--------------+--------------------+
⚐ you can cron if you’re not on the deny list.
⚑ Some systems allow all users, others allow only root.
==================================================================
Generate a log file
To append the command’s output to a log file:
15 5 * * * some_command >> /home/someuser/logs/cron/some_command.log
To overwrite or create a new log file:
15 5 * * * some_command > /home/someuser/logs/cron/some_command.log
To log errors:
15 5 * * * some_command 2> /home/someuser/logs/cron/errors.log
==================================================================
Gotchas
- if the crontab -e command is available, you should not attempt to edit cronjobs otherwise.
- when you edit crontab with crontab -e, it opens with whatever editor is currently set in the shell’s $EDITOR variable. To change this temporarily (i.e. for the current shell window), from the command line type
$ export EDITOR=nano
No space around the = sign. crontab -e will now open with the nano editor. echo $EDITOR tells you which editor is currently set. To make the change permanent, put the export command in your profile’s init script (.profile, .bashrc, etc).
- percent symbols (%) indicate new lines in cron job entries. To use them in the context of a command, escape them with a backslash (e.g. date +\%m).
- prior to running jobs, cron sets a minimal environment that may or may not include /usr/bin in its $PATH variable. It’s therefore generally a good idea to specify the full path to a command in crontab. To find out what that path is, from the shell type
$ which somecommand
- also, to run jobs in your crontab, cron sets its $HOME variable to your $HOME variable (i.e. You, the owner of the crontab file).
- if you wish for your profile initialization script to be executed prior to a job, you must explicitly specify it in that job’s entry. e.g.
0 6 * * * $HOME/.profile && daily_backup.sh
- the location of cron.allow and cron.deny may vary across Unixes. In Linux they’re under /etc, whereas in Solaris for example they’re under /etc/cron.d.


