Cron and Task Scheduling | Linux
cron Daemon
Section titled “cron Daemon”The cron daemon (crond) is a time-based job scheduler that runs commands at specified times and Intervals. It wakes up every minute, checks all crontab files for matching time specifications, and Executes due commands.
## Check if cron is runningsystemctl status cron # Debian/Ubuntusystemctl status crond # Fedora/RHEL
## Start/enable cronsystemctl enable --now cronsystemctl enable --now crondCrontab Format
Section titled “Crontab Format”Time Fields
Section titled “Time Fields”# .---------------- minute (0 - 59)# | .------------- hour (0 - 23)# | | .---------- day of month (1 - 31)# | | | .------- month (1 - 12)# | | | | .---- day of week (0 - 6, 0 = Sunday)# | | | | |# * * * * * command# Examples* * * * * /usr/bin/command # every minute*/5 * * * * /usr/bin/command # every 5 minutes0 * * * * /usr/bin/command # every hour (at minute 0)0 2 * * * /usr/bin/command # every day at 2:00 AM0 0 * * 0 /usr/bin/command # every Sunday at midnight0 0 1 * * /usr/bin/command # first of every month at midnight0 0 1 1 * /usr/bin/command # January 1 at midnight30 4 1,15 * * /usr/bin/command # 1st and 15th at 4:30 AM0 9-17 * * 1-5 /usr/bin/command # every hour 9-17 on weekdays0 */2 * * * /usr/bin/command # every 2 hours15 6 * * 2-6 /usr/bin/command # 6:15 AM, Tuesday through SaturdaySpecial Strings
Section titled “Special Strings”| String | Equivalent | Description |
|---|---|---|
@yearly | 0 0 1 1 * | Once per year |
@annually | 0 0 1 1 * | Same as @yearly |
@monthly | 0 0 1 * * | Once per month |
@weekly | 0 0 * * 0 | Once per week |
@daily | 0 0 * * * | Once per day |
@midnight | 0 0 * * * | Same as @daily |
@hourly | 0 * * * * | Once per hour |
@reboot | (special) | Run once at cron daemon startup |
# System backup every day at midnight@daily /usr/local/bin/backup.sh
# Weekly report every Monday at 6 AM@weekly /usr/local/bin/generate-report.sh
# Cleanup on reboot@reboot /usr/local/bin/cleanup.shAdvanced Time Specifications
Section titled “Advanced Time Specifications”# Step values*/15 * * * * # every 15 minutes1-31/2 * * * * # every other day of the month (1,3,5,...,31)
# Range with step0 6-18/2 * * * # every 2 hours from 6 AM to 6 PM (6,8,10,...,18)
# Day of week with day of month (both must match)0 0 15 * 1 # 15th of the month AND Monday (not common)# To specify "15th OR Monday", use two separate lines:0 0 15 * * # 15th of every month0 0 * * 1 # every Monday
# Lists0 0 * * 1,3,5 # Monday, Wednesday, FridayCrontab Commands
Section titled “Crontab Commands”# Edit user"s crontabcrontab -e
# List user's crontabcrontab -l
# Remove user's crontabcrontab -r
# Remove with confirmationcrontab -i -r
# Edit another user's crontab (root only)crontab -e -u usernamecrontab -l -u username
# Replace crontab from filecrontab crontab_file.txt
# Validate crontab syntax (some implementations)crontab -l 2>&1 | head -1cron Environment
Section titled “cron Environment”Environment Variables in Crontab
Section titled “Environment Variables in Crontab”# Crontab environment is minimal — NOT the same as interactive shell# These are the defaults set by cron:# SHELL=/bin/sh# HOME=/home/username (or /root)# LOGNAME=username
# Set environment variables in crontabSHELL=/bin/bashPATH=/usr/local/bin:/usr/bin:/binJAVA_HOME=/usr/lib/jvm/java-11LANG=en_US.UTF-8
# These take effect for all subsequent cron entries*/5 * * * * /usr/local/bin/myapp --config /etc/myapp.confPATH Issues
Section titled “PATH Issues”# WRONG — command not found in cron's minimal PATH* * * * * python3 /path/to/script.py# /bin/sh: python3: command not found
# CORRECT — use full paths* * * * * /usr/bin/python3 /path/to/script.py
# CORRECT — set PATH in crontabPATH=/usr/local/bin:/usr/bin:/bin* * * * * python3 /path/to/script.py
# CORRECT — source environment in the script* * * * * /bin/bash -c 'source ~/.bashrc && python3 /path/to/script.py'MAILTO
Section titled “MAILTO”# Send cron output via emailMAILTO=admin@example.com0 2 * * * /usr/local/bin/backup.sh
# Disable email for a specific jobMAILTO=""0 * * * * /usr/local/bin/check_health.sh
# Send to multiple addressesMAILTO="admin@example.com,oncall@example.com"cron Permissions
Section titled “cron Permissions”# /etc/cron.allow — if it exists, only listed users can use cron# /etc/cron.deny — if it exists, listed users CANNOT use cron## Priority: cron.allow > cron.deny# If neither exists: only root can use cron (varies by distribution)# If both exist: cron.allow takes precedence
# Create /etc/cron.allowecho "admin" | sudo tee -a /etc/cron.allowecho "deploy" | sudo tee -a /etc/cron.allow
# Create /etc/cron.denyecho "nobody" | sudo tee -a /etc/cron.denySystem cron
Section titled “System cron”/etc/crontab
Section titled “/etc/crontab”# /etc/crontab — system-wide crontab# Format includes a username field (unlike user crontabs)SHELL=/bin/bashPATH=/sbin:/bin:/usr/sbin:/usr/binMAILTO=root
# For details see man 4 crontabs
# Example of system crontab entries# m h dom mon dow user command17 * * * * root cd / && run-parts --report /etc/cron.hourly25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )/etc/cron.d/
Section titled “/etc/cron.d/”# Drop-in directory for application cron jobs# Files must be owned by root and not writable by group/other
SHELL=/bin/bashPATH=/sbin:/bin:/usr/sbin:/usr/bin* * * * * appuser /usr/local/bin/myapp-health-check
# /etc/cron.d/logrotateSHELL=/bin/bash*/15 * * * * root /usr/sbin/logrotate /etc/logrotate.conf
# Permissions on cron.d files must be 0644chmod 644 /etc/cron.d/myappchown root:root /etc/cron.d/myapp/etc/cron.hourly, cron.daily, cron.weekly, cron.monthly
Section titled “/etc/cron.hourly, cron.daily, cron.weekly, cron.monthly”# Scripts in these directories are run by run-parts# Scripts must be executable and not have dots or other special characters in filenames
# List scheduled scriptsls -la /etc/cron.daily/# logrotate man-db.cron ...
# Add a daily jobcat > /etc/cron.daily/my-daily-job << 'EOF'#!/bin/bash/usr/local/bin/daily-maintenanceEOFchmod 755 /etc/cron.daily/my-daily-jobanacron
Section titled “anacron”anacron (anachronistic cron) is designed for systems that are not running 24/7. Unlike cron, which Assumes the system is always on, anacron ensures that jobs run at the specified intervals relative To the last run, even if the system was off.
# anacron configurationcat /etc/anacrontab# /etc/anacrontab: configuration file for anacron# See anacron(8) and anacrontab(5) for details.## period delay job-identifier command1 5 cron.daily nice run-parts --report /etc/cron.daily7 10 cron.weekly nice run-parts --report /etc/cron.weekly@monthly 15 cron.monthly nice run-parts --report /etc/cron.monthly
# period: number of days between runs# delay: minutes to wait after anacron starts before running# job-identifier: unique name (used for timestamp files in /var/spool/anacron/)# command: the command to run# Run anacron manuallyanacron -n # run all jobs now (no delay)anacron -s # run jobs synchronouslyanacron -f # force jobs to run (ignore timestamps)anacron -t # test configuration (dry run)
# Check timestampsls -la /var/spool/anacron/# cron.daily cron.monthly cron.weeklycron vs anacron
Section titled “cron vs anacron”| Feature | cron | anacron |
|---|---|---|
| System type | 24/7 servers | Desktops, laptops |
| Missed jobs | Skipped | Run at next opportunity |
| Granularity | 1-minute precision | Daily minimum |
| Runs at | Exact specified times | After boot (with delay) |
| Per-user | Yes | No (system-wide only) |
| Suitable for | Precise scheduling | Ensuring periodic tasks run |
systemd Timers
Section titled “systemd Timers”Systemd timers provide an alternative to cron with tighter integration into the systemd ecosystem.
Timer Unit Files
Section titled “Timer Unit Files”[Unit]Description=Daily backup timer
[Timer]# Calendar expression (systemd.time calendar format)OnCalendar=*-*-* 02:00:00
# Run immediately if a scheduled run was missed# (e.g., system was off at 2 AM)Persistent=true
# Randomize start time by up to 10 minutes# (prevents thundering herd on many systems)RandomizedDelaySec=10m
# Accuracy — timer may fire this much late (default 1 min)AccuracySec=1min
[Install]WantedBy=timers.target[Unit]Description=Daily backup
[Service]Type=oneshotExecStart=/usr/local/bin/backup.shUser=backupGroup=backupOnCalendar Syntax
Section titled “OnCalendar Syntax”# systemd calendar expressions (see systemd.time(7))OnCalendar=*-*-* 02:00:00 # daily at 2 AMOnCalendar=Mon *-*-* 03:00:00 # every Monday at 3 AMOnCalendar=*-*-01 00:00:00 # first of every monthOnCalendar=Mon..Fri *-*-* 09:00:00 # weekdays at 9 AMOnCalendar=*-*-* 00/3:00:00 # every 3 hoursOnCalendar=hourly # same as aboveOnCalendar=daily # every day at midnightOnCalendar=weekly # every Monday at midnightOnCalendar=monthly # first of every monthOnCalendar=quarterly # every 3 monthsOnCalendar=semi-annually # every 6 monthsOnCalendar=yearly # every yearOnCalendar=*-*-* 02:00:00 UTC # daily at 2 AM UTCOnCalendar=Mon,Fri *-*-* 17,18:00:00 # Mon and Fri at 5 PM and 6 PM
# Validate a calendar expressionsystemd-analyze calendar '*-*-* 02:00:00'systemd-analyze calendar 'Mon..Fri *-*-* 09:00:00'
# Show next scheduled runssystemd-analyze calendar --iterations=5 'Mon *-*-* 03:00:00'Managing Timers
Section titled “Managing Timers”# List all timerssystemctl list-timers --all
# List timers for a specific unitsystemctl list-timers backup.timer
# Enable and start a timersystemctl enable --now backup.timer
# Stop and disablesystemctl stop backup.timersystemctl disable backup.timer
# Check timer statussystemctl status backup.timer
# View timer logsjournalctl -u backup.timerjournalctl -u backup.service
# Show timer calendarsystemctl show backup.timer --property=NextElapseUSecRealtimesystemd Timers vs cron
Section titled “systemd Timers vs cron”| Feature | cron | systemd timer |
|---|---|---|
| Boot catch-up | No (missed jobs skipped) | Yes (Persistent=true) |
| Logging | Email or /var/log/syslog | journald |
| Dependencies | None | Full systemd dependency |
| Resource limits | System defaults | Per-service limits |
| Randomized delay | No | RandomizedDelaySec |
| Calendar syntax | cron expression | systemd calendar events |
| Per-user timers | Yes | Yes (--user) |
| Precision | 1 minute | 1 minute (AccuracySec) |
| Built-in monitoring | No | Yes (systemctl status) |
| Timezone handling | System timezone | Per-timer Timezone= |