Scheduled Tasks

Cron scheduling syntax, anacron for non-persistent systems, and systemd timer units as the modern alternative.

Crontab Management

Edit your crontab
crontab -e
List your crontab entries
crontab -l
Remove your entire crontab — no confirmation, be careful
crontab -r
Edit crontab for another user (root only)
sudo crontab -u jdoe -e
List another user’s crontab
sudo crontab -u jdoe -l

Cron Syntax

The five time fields
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12 or jan-dec)
│ │ │ │ ┌───────────── day of week (0-7, 0 and 7 are Sunday, or sun-sat)
│ │ │ │ │
* * * * * command
Every 5 minutes
*/5 * * * * /usr/local/bin/check-health.sh
Every day at 2:30 AM
30 2 * * * /usr/local/bin/daily-backup.sh
Every Monday at 6:00 AM
0 6 * * 1 /usr/local/bin/weekly-report.sh
First day of every month at midnight
0 0 1 * * /usr/local/bin/monthly-cleanup.sh
Every weekday (Mon-Fri) at 8 AM
0 8 * * 1-5 /usr/local/bin/workday-start.sh
Every 15 minutes during business hours
*/15 8-17 * * 1-5 /usr/local/bin/monitor.sh

Shortcut Strings

Predefined scheduling shortcuts — use instead of memorizing field combinations
@reboot     Run once at startup
@hourly     0 * * * *
@daily      0 0 * * *      (also @midnight)
@weekly     0 0 * * 0
@monthly    0 0 1 * *
@yearly     0 0 1 1 *      (also @annually)
Run a script at boot
@reboot /usr/local/bin/startup-init.sh

Environment Gotchas

Cron runs with a minimal environment. Commands that work in your shell may fail in cron.

Set PATH explicitly — the #1 cron debugging issue
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash

*/5 * * * * /usr/local/bin/my-script.sh
Use absolute paths for everything — cron doesn’t source your .bashrc
# Wrong
*/5 * * * * my-script.sh

# Correct
*/5 * * * * /usr/local/bin/my-script.sh
Set MAILTO to receive cron errors via email
MAILTO=admin@example.com

0 2 * * * /usr/local/bin/backup.sh
Suppress output — only if you truly don’t want error notifications
0 2 * * * /usr/local/bin/backup.sh > /dev/null 2>&1
Sending stderr to /dev/null hides failures. Redirect to a log file instead.

Logging Cron Output

Redirect stdout and stderr to a log file
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Timestamped log entries
0 2 * * * /usr/local/bin/backup.sh 2>&1 | ts '[%Y-%m-%d %H:%M:%S]' >> /var/log/backup.log
Check cron execution in the journal
journalctl -u crond --since today

System Cron Directories

/etc/crontab — system crontab with a USER field (6th field before command)
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin

# minute hour day month dow user  command
*/10    *    *   *    *   root  /usr/local/bin/system-check.sh
/etc/cron.d/ — drop-in crontab files, same format as /etc/crontab (includes user field)
ls /etc/cron.d/
/etc/cron.{hourly,daily,weekly,monthly}/ — drop scripts here, no cron syntax needed
ls /etc/cron.daily/

Scripts in these directories must be executable and must NOT have a file extension (no .sh). The run-parts command that executes them skips files with dots in the name.

Access Control

/etc/cron.allow — if it exists, ONLY listed users can use cron
sudo cat /etc/cron.allow
/etc/cron.deny — listed users are BLOCKED from using cron
sudo cat /etc/cron.deny

Priority: if cron.allow exists, cron.deny is ignored. If neither exists, only root can use cron (on RHEL; behavior varies by distro).

Anacron

Anacron handles jobs on systems that aren’t always on. It guarantees a job runs at least once per period, even if the machine was off during the scheduled time.

/etc/anacrontab format
# period  delay  job-id         command
1         5      cron.daily     nice run-parts /etc/cron.daily
7         25     cron.weekly    nice run-parts /etc/cron.weekly
@monthly  45     cron.monthly   nice run-parts /etc/cron.monthly

Period is in days. Delay is minutes after anacron starts. Timestamps in /var/spool/anacron/ track last execution.

Systemd Timers vs Cron

List active systemd timers
systemctl list-timers --all
Key differences
Feature          cron                    systemd timer
───────────────────────────────────────────────────────
Logging          mail/redirect           journalctl -u
Dependencies     none                    After=, Requires=
Missed runs      anacron (daily+)        Persistent=true
Resource limits  none                    CPUQuota=, MemoryMax=
User scope       crontab -e              systemctl --user
Randomized delay no                      RandomizedDelaySec=

For RHCSA, know both. Cron is tested directly. Systemd timers are the modern replacement.

See Also

  • systemd — timer units as cron replacement