Home/Learn/Linux/Cron, at & Automation

Cron, at & Automation

Intermediate
Automation

cron runs commands on a schedule; at runs a command once at a specified future time. These are the standard Linux tools for backup jobs, report generation, and routine maintenance.

Overview

cron is a daemon that wakes up every minute and checks crontab files for commands to run. A crontab entry has five time fields (minute, hour, day, month, weekday) followed by the command. cron runs commands in a minimal environment — it does not source your .bashrc, so always use absolute paths. Systemd timers are the modern alternative (more features, journald logging, dependency management) but cron is still ubiquitous and worth knowing thoroughly.

Crontab Syntax

The five time fields control when the command runs. The asterisk * means "every". A common mistake is forgetting that cron runs in a minimal environment without your normal PATH.

Crontab time field syntax
# Crontab format:
# ┌──────────── minute (0 - 59)
# │ ┌────────── hour (0 - 23)
# │ │ ┌──────── day of month (1 - 31)
# │ │ │ ┌────── month (1 - 12)
# │ │ │ │ ┌──── day of week (0=Sun, 6=Sat, 7=Sun)
# │ │ │ │ │
# * * * * *   command to execute

# Examples:
* * * * *    /opt/scripts/heartbeat.sh         # every minute
0 * * * *    /opt/scripts/hourly-report.sh      # every hour at :00
0 2 * * *    /opt/scripts/backup.sh             # daily at 2:00 AM
0 2 * * 0    /opt/scripts/weekly-cleanup.sh     # Sundays at 2:00 AM
0 0 1 * *    /opt/scripts/monthly-invoice.sh    # 1st of every month, midnight
*/5 * * * *  /opt/scripts/health-check.sh       # every 5 minutes
0 9-17 * * 1-5 /opt/scripts/business-hours.sh  # every hour, 9-5, Mon-Fri

# Shortcuts
@reboot      /opt/scripts/startup.sh            # on system boot
@daily       /opt/scripts/backup.sh             # same as: 0 0 * * *
@weekly      /opt/scripts/cleanup.sh            # same as: 0 0 * * 0
@monthly     /opt/scripts/report.sh             # same as: 0 0 1 * *

# crontab.guru — visual cron expression editor online

Managing Crontabs

Each user has their own crontab. System-wide crontabs live in /etc/cron.d/. Cron runs in a minimal shell environment — always use absolute paths and set PATH explicitly.

bash — crontab management
# Edit your crontab
crontab -e          # opens in $EDITOR (usually nano or vi)
crontab -l          # list current crontab
crontab -r          # remove crontab ⚠️ no confirmation!

# Root crontab (for system tasks)
sudo crontab -e
sudo crontab -l

# System crontab locations:
# /etc/crontab           → system-wide crontab (has extra 'user' field)
# /etc/cron.d/           → drop-in crontab files
# /etc/cron.daily/       → scripts run daily
# /etc/cron.hourly/      → scripts run hourly

# Example: /etc/cron.d/myapp
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=admin@company.com    # email output to admin (empty = no email)

0 2 * * * appuser /opt/myapp/scripts/backup.sh >> /var/log/myapp-backup.log 2>&1

# Common cron pitfalls:
# 1. PATH is minimal — use absolute paths: /usr/bin/python3 not python3
# 2. No home directory expansion — use $HOME or /home/user explicitly
# 3. Output goes to email (MAILTO) or is discarded — redirect to log file
# 4. % is special in crontab — escape with % or use a script file

# Verify cron is running
systemctl status cron       # Debian/Ubuntu
systemctl status crond      # RHEL/CentOS

Systemd Timers — Modern Alternative

Systemd timers replace cron for new deployments: they use journald for logging, support dependencies, and can be activated relative to system events.

systemd timer — modern cron replacement
# Two files needed: a .timer unit and a .service unit

# /etc/systemd/system/backup.service
[Unit]
Description=Daily database backup
After=postgresql.service

[Service]
Type=oneshot                # exits when done (not a daemon)
User=postgres
ExecStart=/opt/scripts/backup.sh
StandardOutput=journal
StandardError=journal

# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 2 AM

[Timer]
OnCalendar=*-*-* 02:00:00      # daily at 2 AM (systemd calendar syntax)
# OnCalendar=weekly             # shorthand: weekly on Monday 00:00
# OnBootSec=5min                # 5 minutes after boot
# OnUnitActiveSec=1h            # 1 hour after last activation
Persistent=true                 # run immediately if last run was missed

[Install]
WantedBy=timers.target

# Deploy
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

# Manage
systemctl list-timers                    # show all timers and next run time
systemctl status backup.timer
journalctl -u backup.service             # logs from timer-triggered runs
systemctl start backup.service           # trigger manually for testing

Key Points to Remember

  • 1Crontab fields: minute hour day month weekday — remember with "minute or hour, day or month, weekday".
  • 2Always use absolute paths in crontab — cron runs with a minimal PATH.
  • 3Redirect cron job output to a log file: command >> /var/log/job.log 2>&1.
  • 4@reboot runs a command once at system startup — useful for background services.
  • 5Systemd timers offer journald logging, dependency management, and catch-up on missed runs.
  • 6crontab.guru is the fastest way to verify a cron expression.

Interview Questions

Sign in to ask Aria
1

How do you run a cron job every 5 minutes?

2

A cron job works when run manually but fails when run by cron. Why?

Ask Aria about Cron, at & Automation

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…