Cron + scheduling cheatsheet.

crontab

crontab -e                          # edit your cron
crontab -l                          # list
crontab -r                          # remove all
crontab -u alice -e                 # edit alice's (root only)
sudo crontab -e                     # root's

Syntax

m h dom mon dow command
* * * * * /opt/script.sh

# minute (0-59)
# hour (0-23)
# day of month (1-31)
# month (1-12)
# day of week (0-7, 0/7 = sunday)

Examples:

0 2 * * *           daily 02:00
*/15 * * * *        every 15 min
0 */2 * * *         every 2 hours
0 0 * * 0           weekly Sunday midnight
0 0 1 * *           monthly 1st
0 9-17 * * 1-5      hourly 9-5 weekdays
@reboot             on boot
@daily              daily midnight
@hourly

Environment

Cron has minimal environment. Set explicitly:

SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
[email protected]

0 2 * * * /opt/script.sh

/etc/crontab

System cron with user field:

m h dom mon dow user command
0 2 * * * root /opt/backup.sh

/etc/cron.d/, hourly/, daily/, etc

Drop-in directories. /etc/cron.daily/ runs via run-parts.

anacron

For systems not always on. Catches up missed runs.

/etc/anacrontab:

1   5   cron.daily   run-parts /etc/cron.daily
7   25  cron.weekly  run-parts /etc/cron.weekly

period / delay / job-id / command.

Logging

Cron logs to syslog/journal:

journalctl -u cron
journalctl -u crond              # RHEL

Redirect script output:

0 2 * * * /opt/backup.sh > /var/log/backup.log 2>&1

Capture failures

0 2 * * * /opt/backup.sh || curl -fsS https://hc-ping.com/UUID/fail

Better: healthchecks.io / cronitor:

0 2 * * * curl -fsS https://hc-ping.com/UUID/start && /opt/backup.sh && curl -fsS https://hc-ping.com/UUID

systemd timer (alternative)

# backup.timer
[Unit]
Description=Daily backup

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=600

[Install]
WantedBy=timers.target
# backup.service
[Unit]
Description=Backup

[Service]
Type=oneshot
ExecStart=/opt/backup.sh
systemctl enable --now backup.timer
systemctl list-timers

Advantages over cron:

  • Integration with journal.
  • Service-style env / sandboxing.
  • Random delay.
  • Dependencies.
  • Persistent=true catches up missed.

at (one-time)

at 14:00 << EOF
echo "task" | mail alice
EOF

atq                                 # list pending
atrm 1

Locking (prevent overlap)

0 2 * * * flock -n /tmp/backup.lock /opt/backup.sh

Or in systemd: services serialize automatically.

Idempotency

Cron may overlap if jobs run long. Either:

  • Use flock.
  • Make script check + skip if already running.
  • systemd unit with RemainAfterExit=yes for one-shot semantics.

Common mistakes

  • Cron PATH differs from shell → “command not found”.
  • Forgetting absolute paths in scripts.
  • Long-running job overlaps itself.
  • Logs lost — redirect or MAILTO.
  • DST changes cause double/missed runs.
  • MAILTO not set → output silently dropped (no MTA).

Read this next

If you want my healthchecked cron setup, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .