HxHippy

Cron Jobs and Task Scheduling

Automate tasks with cron, systemd timers, and at commands.

Last updated: 2024-12-18

Automate recurring tasks with Linux's built-in scheduling tools. Master cron for reliable task automation.

Cron Basics

Cron runs scheduled tasks called "cron jobs" based on time expressions.

Crontab Syntax

* * * * * command
| | | | |
| | | | +-- Day of week (0-7, Sun=0 or 7)
| | | +---- Month (1-12)
| | +------ Day of month (1-31)
| +-------- Hour (0-23)
+---------- Minute (0-59)

Examples

# Every minute
* * * * * /path/to/script.sh

# Every hour at minute 30
30 * * * * /path/to/script.sh

# Every day at 2:30 AM
30 2 * * * /path/to/script.sh

# Every Monday at 9 AM
0 9 * * 1 /path/to/script.sh

# First day of every month at midnight
0 0 1 * * /path/to/script.sh

# Every 15 minutes
*/15 * * * * /path/to/script.sh

# Every weekday at 6 PM
0 18 * * 1-5 /path/to/script.sh

# Twice daily (9 AM and 6 PM)
0 9,18 * * * /path/to/script.sh

Special Strings

@reboot     # Run once at startup
@yearly     # 0 0 1 1 *
@annually   # Same as @yearly
@monthly    # 0 0 1 * *
@weekly     # 0 0 * * 0
@daily      # 0 0 * * *
@midnight   # Same as @daily
@hourly     # 0 * * * *

Managing Crontabs

# Edit your crontab
crontab -e

# View your crontab
crontab -l

# Remove your crontab
crontab -r

# Edit another user's crontab (root)
sudo crontab -u username -e

# View system-wide crontab
cat /etc/crontab

System Cron Directories

# Drop scripts in these directories:
/etc/cron.d/        # Custom cron files
/etc/cron.hourly/   # Run every hour
/etc/cron.daily/    # Run daily
/etc/cron.weekly/   # Run weekly
/etc/cron.monthly/  # Run monthly

# Scripts must be executable and have no extension
sudo cp backup.sh /etc/cron.daily/backup
sudo chmod +x /etc/cron.daily/backup

Best Practices

Use Absolute Paths

# BAD - might not find commands
0 2 * * * backup.sh

# GOOD - explicit paths
0 2 * * * /usr/local/bin/backup.sh

Set PATH and Environment

# At top of crontab
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
SHELL=/bin/bash
MAILTO=[email protected]

0 2 * * * /usr/local/bin/backup.sh

Redirect Output

# Silence output (no mail)
0 2 * * * /path/to/script.sh > /dev/null 2>&1

# Log output
0 2 * * * /path/to/script.sh >> /var/log/backup.log 2>&1

# Log with timestamp
0 2 * * * /path/to/script.sh >> /var/log/backup.log 2>&1 && echo "---\n$(date)" >> /var/log/backup.log

Prevent Overlap

# Use flock to prevent concurrent runs
* * * * * /usr/bin/flock -n /tmp/myjob.lock /path/to/script.sh

# Or check in the script
#!/bin/bash
LOCKFILE=/tmp/myjob.lock
if [ -f "$LOCKFILE" ]; then
    echo "Job already running"
    exit 1
fi
trap "rm -f $LOCKFILE" EXIT
touch "$LOCKFILE"
# ... rest of script

Systemd Timers (Modern Alternative)

Create Timer Unit

# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Create Service Unit

# /etc/systemd/system/backup.service
[Unit]
Description=Backup service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=backup

Enable Timer

sudo systemctl daemon-reload
sudo systemctl enable backup.timer
sudo systemctl start backup.timer

# View timer status
systemctl list-timers
systemctl status backup.timer

OnCalendar Examples

OnCalendar=hourly
OnCalendar=daily
OnCalendar=weekly
OnCalendar=*-*-* 02:00:00       # Daily at 2 AM
OnCalendar=Mon *-*-* 09:00:00   # Monday at 9 AM
OnCalendar=*-*-01 00:00:00      # First of month
OnCalendar=*:0/15               # Every 15 minutes

One-Time Tasks with at

# Run command at specific time
echo "/path/to/script.sh" | at 2:00 AM

# Run tomorrow
at tomorrow <<< "/path/to/script.sh"

# Run in 2 hours
at now + 2 hours <<< "/path/to/script.sh"

# Interactive mode
at 14:30
at> /path/to/script.sh
at> Ctrl+D

# List scheduled jobs
atq

# Remove job
atrm job_number

# View job details
at -c job_number

Troubleshooting

Check Cron is Running

systemctl status cron
# or
systemctl status crond

View Cron Logs

# Debian/Ubuntu
grep CRON /var/log/syslog

# RHEL/CentOS
grep cron /var/log/cron

# Systemd journal
journalctl -u cron

Test Cron Environment

# See what environment cron uses
* * * * * env > /tmp/cron-env.txt

# Then compare
diff /tmp/cron-env.txt <(env)

Common Issues

  1. Script works manually but not in cron

    • Check PATH and use absolute paths
    • Check file permissions
    • Check environment variables
  2. No output/mail

    • Check MAILTO setting
    • Check if mail is configured
    • Redirect output to log file
  3. Wrong timezone

    • Check TZ in crontab
    • System timezone: timedatectl
intermediate System Administration 20 min read

Related Tutorials

croncrontabschedulingsystemd timerautomationat