cron is a background program that runs on almost every Linux server.
Its task is to start commands or scripts at fixed times, for example, every day at 3:00 am or every Sunday at 11:00 pm. cron is controlled by the /etc/crontab file, whose somewhat strange syntax I will explain in a moment.
cron is installed by default on many Linux distributions. If the /etc/crontab file does not exist on your system, you can easily resolve the situation:
$ sudo apt update && sudo install cron (Debian, Ubuntu)
$ sudo dnf install cronie && \ (Fedora, RHEL)
sudo systemctl enable --now crond
The following lines show an excerpt from a crontab file:
# File /etc/crontab
# every day at 3:00 am: Backup
0 3 * * * root /etc/myscripts/backup.sh
# on the first day of each month at 0:00:
# statistical analysis of login data
0 0 1 * * root /etc/myscripts/statistics.py
crontab files describe the commands to be executed line by line, where each entry is composed of seven columns:
minutes hours day-of-month month weekday user cmd
minutes: 0-59
hours: 0-12
day-of-month: 1-31
month: 1-12
weekday: 0-7 (0 = 7 = Sunday, 1 = Monday, etc.)
user: Account under which the script should be executed (often root)
cmd: The command to execute, often simply the path to a script
Lines beginning with # are comments. The last line of the crontab file must end with a newline character. The following syntax rules apply to the first five columns in the crontab file:
The columns are usually linked by a logical AND. An exception is if day-of-month and weekday are specified; then, a logical OR applies to these two columns. The command is executed both on the nth day of the month and on the specified day of the week.
The following listing contains some syntax examples. You can verify your own cron time compositions at https://crontab.guru.
# every 15 minutes
*/15 * * * * root cmd
# daily at 0:15, 1:15, 2:15, etc.
15 * * * * peter cmd
# daily at 1:30
30 1 * * * maria cmd
# every Saturday at 0:29
29 0 * * 6 root cmd
# on every 1st of the month at 6:25
25 6 1 * * www-data cmd
# on the 1st and 15th of the month and every Monday
# always at midnight
0 0 1,15 * 1 root cmd
Provided that cron jobs are executed on a machine where a mail server is configured, the output or error messages are sent to root@localhost. You can change this address by setting MAILTO=... within /etc/crontab.
Trouble with PATH and LANG: A different PATH default setting applies to cron jobs than in interactive mode. Changes to PATH in .bashrc are not taken into account. For this reason, commands installed outside the usual directories like /usr/bin or /usr/sbin cannot be executed! You should therefore make sure to test whether your script is also executed correctly when started by cron. If necessary, you must specify the full path in the script for manually installed commands, for example, /usr/local/bin/aws to run the Amazon Web Services (AWS) client. Alternatively, for some cron implementations, you can redefine the PATH variable directly in /etc/crontab. There you need to specify all directories in which commands are to be searched for, for example as follows: PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin. Another possible source of errors can be the LANG environment variable, which may have a different setting in cron jobs than when you run your scripts locally. A setting in /etc/crontab like for PATH is not possible. However, you can set LANG at the beginning of your script.
Modifying /etc/crontab requires system administrator privileges. If these privileges are not available to you, you can modify your own crontab file. This file is located in /var/spool/cron/<user> or in /var/spool/cron/crontabs/<user>, depending on the Linux distribution.
You can open your personal crontab file using the crontab -e command. By default, the vi editor is used in this context, which is not user friendly. If you’ve started the program by mistake, you can exit it by pressing (Esc), typing “:q!,” and pressing (Enter) without saving changes. If necessary, you can select a simpler editor via the EDITOR variable before running the crontab command:
$ export EDITOR=/usr/bin/nano
$ crontab -e
Note that the sixth column for the account is omitted in the private crontab file. The command or script is always executed with the rights of your account. This limitation is the biggest disadvantage of this method: Many admin tasks (such as system-wide backups) require root privileges and cannot be performed in “ordinary” accounts. Sudo does not help in this case either because this command requires the interactive input of your password.
If you don’t care about the exact time when your cron tasks are performed, you can save the script to be called in one of the following directories:
The benefit of this method is that you do not need to deal with the crontab syntax. Remember to mark your script file as executable by using chmod +x! Your scripts will be executed with root privileges.
On Linux, systemd-timer is becoming more frequently used. The biggest advantage of systemd-timer compared to cron is that started jobs can be monitored more comprehensively.
But this advantage is offset by a much higher degree of complexity. While setting up a cron job can be done in 30 seconds with a little experience, timer jobs require you create two relatively complex configuration files. A good description of the mechanism can be found on the Arch Linus wiki at https://wiki.archlinux.org/title/Systemd/Timers. This information also applies to other distributions.
cron is also available on macOS but is considered obsolete there. The /etc/crontab file does not exist by default. However, you only need to create the file (for example, using sudo nano /etc/crontab) and insert one correct entry; then, the job will be executed without any further configuration work. In this respect, cron is the simplest solution for automating the script call for macOS until further notice.
Apple recommends using the macOS-specific launchd program instead of cron. The configuration is done by XML files, whose syntax is documented here:
Editor’s note: This post has been adapted from a section of the book Scripting: Automation with Bash, PowerShell, and Python by Michael Kofler.