Cron jobs are the unsung heroes of system administration, quietly executing tasks at predetermined times.
Let’s see cron in action. Imagine you want to back up a critical directory every night at 2 AM.
# This is your crontab file
# Edit with: crontab -e
# m h dom mon dow command
0 2 * * * /usr/local/bin/backup_script.sh >> /var/log/backup.log 2>&1
Here’s what’s happening:
0 2 * * *: This is the schedule. It means at minute0of hour2(2 AM), every day (*), every month (*), and every day of the week (*)./usr/local/bin/backup_script.sh: This is the command to execute. It’s crucial to use the absolute path to your script.>> /var/log/backup.log 2>&1: This redirects both standard output (stdout) and standard error (stderr) to a log file, appending (>>) to it each time. This is vital for debugging.
The problem cron solves is automation. Instead of manually running repetitive tasks like backups, log rotation, or system updates, you can schedule them to run automatically. This frees up your time, reduces the chance of human error, and ensures critical maintenance happens consistently.
Internally, cron works by having a daemon (crond or cron) that wakes up every minute, checks the crontab files for all users, and compares the current time with the scheduled times. If a match is found, it executes the associated command. The system’s crontab file is usually located at /etc/crontab, and user-specific crontabs are stored in /var/spool/cron/.
You control cron jobs through the crontab command.
crontab -e: Edits your current user’s crontab file.crontab -l: Lists your current user’s crontab entries.crontab -r: Removes your current user’s crontab file (use with extreme caution!).
The syntax for the schedule is minute hour day_of_month month day_of_week. Each field can be a number, a range (e.g., 1-5), a list (e.g., 1,10,20), or a step value (e.g., */15 for every 15 minutes).
Let’s break down the fields:
- Minute (0-59): The minute of the hour the command will run.
- Hour (0-23): The hour of the day the command will run (24-hour format).
- Day of Month (1-31): The day of the month the command will run.
- Month (1-12): The month of the year the command will run.
- Day of Week (0-7): The day of the week the command will run. Both
0and7represent Sunday.
Special strings simplify common schedules:
@reboot: Run once at startup.@yearlyor@annually: Run once a year (0 0 1 1 *).@monthly: Run once a month (0 0 1 * *).@weekly: Run once a week (0 0 * * 0).@dailyor@midnight: Run once a day (0 0 * * *).@hourly: Run once an hour (0 * * * *).
When a cron job runs, it executes in a minimal environment. This means it doesn’t inherit your interactive shell’s PATH or other environment variables. Always use absolute paths for commands and scripts, or explicitly set the PATH at the beginning of your crontab file.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
SHELL=/bin/bash
# m h dom mon dow command
0 2 * * * /path/to/my/script.sh
If your script relies on specific environment variables, define them at the top of the crontab file before your job entries.
The most surprising thing about cron is that by default, it emails the output of any job that produces output (both stdout and stderr) to the user who owns the crontab. This is often overlooked and can lead to mailboxes filling up with routine job output, or worse, critical errors being missed because they’re buried in daily "no-op" emails. To prevent this, explicitly redirecting output to a log file, or to /dev/null if you truly don’t need it, is standard practice.
The next thing you’ll want to explore is how to manage cron jobs across multiple servers, which often leads to tools like Ansible or SaltStack for configuration management.