Cron (short for “chronograph”) is a daemon (background service) that runs continuously on Linux systems, executing scheduled tasks at specified intervals. These tasks are called cron jobs.
A cron job is a command or script scheduled to run automatically at fixed times, dates, or intervals. For example:
The cron service is managed by crond (cron daemon), which starts automatically at system boot and runs in the background. crond reads configuration files called crontabs (cron tables) to determine when to execute jobs.
Crontabs define the schedule and commands for cron jobs. There are two types:
Each user (including root) can have their own crontab file, stored in /var/spool/cron/crontabs/ (or /var/spool/cron/ on some systems). Users manage their crontabs with the crontab command (no direct file editing required).
System-wide cron jobs are defined in:
/etc/crontab: A system-wide crontab with an extra field for the user to run the job as./etc/cron.d/: A directory for custom system crontabs (e.g., backup.cron)./etc/cron.hourly/, /etc/cron.daily/, etc., where scripts are executed hourly, daily, etc., by the system.The core of cron is its scheduling syntax. A typical cron job entry has six fields (five for time, one for the command).
* * * * * /path/to/command arg1 arg2
| | | | |
| | | | +-- Day of the Week (0-6) [0=Sunday, 6=Saturday] or (1-7) [1=Sunday, 7=Saturday]; some systems use 7=Sunday
| | | +---- Month (1-12 or Jan-Dec)
| | +------ Day of the Month (1-31)
| +-------- Hour (0-23)
+---------- Minute (0-59)
Cron supports special characters to simplify scheduling:
| Character | Description | Example |
|---|---|---|
* | Wildcard: “every” unit (e.g., every minute, every hour). | * * * * * = Every minute |
/ | Step: “every X units”. | */15 * * * * = Every 15 minutes |
- | Range: “from X to Y”. | 0 9-17 * * 1-5 = 9 AM-5 PM weekdays |
, | List: “X, Y, Z”. | 0 0 1,15 * * = 1st and 15th of every month |
Cron provides shorthand aliases for common intervals:
| Alias | Equivalent | Description |
|---|---|---|
@reboot | N/A | Run once at system startup |
@daily | 0 0 * * * | Run once daily at midnight |
@weekly | 0 0 * * 0 | Run once weekly (Sunday) |
@monthly | 0 0 1 * * | Run once monthly (1st) |
@yearly | 0 0 1 1 * | Run once yearly (Jan 1st) |
crontab CommandUse the crontab command to manage user-specific cron jobs. Key options:
| Command | Description |
|---|---|
crontab -e | Edit your crontab (opens in default editor). |
crontab -l | List your current crontab entries. |
crontab -r | Delete your crontab (use with caution!). |
crontab -i | Prompt before deleting (safer than -r). |
Edit your crontab:
crontab -e
This opens the crontab in your default editor (e.g., nano, vim).
Add a job (e.g., run backup.sh daily at 2 AM):
0 2 * * * /home/user/scripts/backup.sh
Save and exit. The cron daemon will automatically detect the changes.
Verify the job is scheduled:
crontab -l
Let’s walk through practical examples to solidify your understanding.
Goal: Run a backup script every day at 2:00 AM.
Create a backup script (/home/user/scripts/backup.sh):
#!/bin/bash
# backup.sh: Backup Documents to external drive
rsync -av /home/user/Documents/ /mnt/external_drive/backup/
Make the script executable:
chmod +x /home/user/scripts/backup.sh
Add the cron job:
0 2 * * * /home/user/scripts/backup.sh
0 = Minute 0 (2:00).2 = Hour 2 (2 AM).* * * = Every day, every month, every weekday.Goal: Delete log files older than 7 days every Sunday at midnight.
Cron job:
0 0 * * 0 /usr/bin/find /var/log/myapp/ -name "*.log" -mtime +7 -delete
0 0 = Midnight (12:00 AM).* * 0 = Every Sunday (day of week 0).find ... -delete: Delete files older than 7 days (-mtime +7).Goal: Run a script every hour to check CPU usage and log results.
Create health_check.sh (/home/user/scripts/health_check.sh):
#!/bin/bash
LOG_FILE="/home/user/logs/health.log"
DATE=$(date "+%Y-%m-%d %H:%M:%S")
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')
echo "[$DATE] CPU Usage: $CPU_USAGE%" >> $LOG_FILE
Make it executable:
chmod +x /home/user/scripts/health_check.sh
Cron job (run every hour):
0 * * * * /home/user/scripts/health_check.sh
0 * = At minute 0 of every hour (e.g., 1:00 AM, 2:00 AM, etc.).Goal: Start a custom service automatically when the system boots.
Cron job (using @reboot shorthand):
@reboot /home/user/scripts/start_my_service.sh
Goal: Receive an email when a job finishes (useful for monitoring).
By default, cron sends job output to the user’s email. To explicitly set the recipient:
MAILTO="[email protected]"
0 12 * * * /home/user/scripts/report.sh
If report.sh outputs text, [email protected] will receive it via email.
Cron runs jobs with a minimal environment (e.g., limited PATH). To avoid “command not found” errors:
/usr/bin/rsync instead of rsync).PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
MAILTO="[email protected]"
0 2 * * * /home/user/scripts/backup.sh
By default, cron sends output to the user’s email. To log to a file instead:
0 2 * * * /home/user/scripts/backup.sh >> /home/user/logs/backup.log 2>&1
>>: Append output to backup.log.2>&1: Redirect errors (stderr) to the same file as output (stdout).Cron relies on the system being running at the scheduled time. For laptops or desktops that are often off, anacron ensures jobs run when the system boots (e.g., a daily job will run 5 minutes after startup if the system was off at 2 AM).
Anacron jobs are defined in /etc/anacrontab (system-wide) or ~/.anacron (user-specific). Example:
# /etc/anacrontab entry: Run backup daily, with a 5-minute delay after boot
1 5 daily_backup /home/user/scripts/backup.sh
Cron has a limited PATH, so always use absolute paths for commands and files:
# Bad: Relies on PATH
0 2 * * * backup.sh
# Good: Absolute path
0 2 * * * /home/user/scripts/backup.sh
Run scripts manually before scheduling them to ensure they work:
/home/user/scripts/backup.sh # Test backup.sh
Always log job output to debug issues later:
0 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
Schedule CPU/disk-intensive jobs (e.g., backups) during off-peak times (e.g., 2 AM) to avoid slowing down the system.
Document jobs for clarity:
# Daily backup of Documents folder (2 AM)
0 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
Save your crontab to a file for backup:
crontab -l > my_crontab_backup.txt
Control who can use cron with:
/etc/cron.allow: Users listed here can use cron (empty = all allowed)./etc/cron.deny: Users listed here cannot use cron (ignored if cron.allow exists).If a cron job isn’t running as expected, check these common issues:
Use crontab -e to validate syntax (it will alert you to errors).
Cron’s PATH is minimal. Verify commands with absolute paths:
which rsync # Output: /usr/bin/rsync → use this path in cron
Ensure the script has execute permissions:
chmod +x /home/user/scripts/backup.sh
Cron uses the system’s time zone. Verify with:
timedatectl # Check "Time zone"
Cron logs are usually stored in /var/log/cron (RHEL/CentOS) or via journalctl (systemd systems):
journalctl -u cron # View cron logs
Cron jobs are a cornerstone of Linux automation, enabling you to streamline repetitive tasks, reduce errors, and save time. By mastering cron syntax, managing crontabs effectively, and following best practices like logging and testing, you can automate everything from backups to system monitoring with confidence.
Remember: Start small (e.g., a daily backup), test rigorously, and gradually expand your automation workflow. With cron in your toolkit, you’ll transform from a manual task-doer to an efficient system automator.