iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

cron

Cron schedules commands to run at regular times. Five time fields + the command. crontab -e for per-user; /etc/cron.d/* for system. Modern Linux uses systemd timers for richer scheduling.

Schedule format + systemd timers

EXAMPLE
# 1) crontab format
#   minute hour day-of-month month day-of-week  command
#   0-59   0-23 1-31         1-12  0-7 (0,7 = Sunday)
#
# Every 5 min:        */5 * * * *
# Top of every hour:  0 * * * *
# Daily at 02:30:     30 2 * * *
# Mondays at 09:00:   0 9 * * 1
# 1st of month, 04:00: 0 4 1 * *
# Every 15 min, business hours: */15 9-17 * * 1-5

# 2) Common shortcuts (some implementations)
# @reboot     — run once at boot
# @yearly     — Jan 1 00:00
# @monthly    — 1st 00:00
# @weekly     — Sunday 00:00
# @daily      — 00:00
# @hourly     — top of hour

# 3) Edit your user crontab
crontab -e                                # opens $EDITOR
crontab -l                                # list
crontab -r                                # remove ALL (careful!)
crontab -u www-data -l                    # another user's (as root)

# Example user crontab:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=ops@example.com
SHELL=/bin/bash

# Backup database every day at 02:00
0 2 * * * /opt/myapp/bin/backup.sh > /var/log/backup.log 2>&1

# Weekly cleanup
0 3 * * 0 find /tmp -type f -mtime +7 -delete

# Every minute health check
* * * * * /opt/myapp/bin/healthcheck.sh

# 4) Important — capture output
#   * * * * * /path/to/cmd                 # output emailed to MAILTO if set
#   * * * * * /path/to/cmd > /var/log/cmd.log 2>&1   # redirect
#   * * * * * /path/to/cmd > /dev/null 2>&1          # silence (lose errors!)

# 5) Environment
# Cron jobs run with a MINIMAL environment — almost no PATH, no aliases.
# - Use absolute paths to binaries OR set PATH at the top of crontab
# - Source /etc/profile if you depend on bash login env:
#       * * * * * . /etc/profile; /opt/myapp/bin/cmd

# 6) System cron — /etc/cron.d/<name>
# Same syntax PLUS a 'user' field after the time fields:
#   0 2 * * * www-data /opt/myapp/bin/backup.sh

# /etc/cron.{daily,hourly,weekly,monthly}/  — drop a script; runs with default schedule

# 7) Logging
# Most distros log cron activity to:
#   /var/log/cron   (RHEL/CentOS)
#   /var/log/syslog (Debian/Ubuntu)
grep CRON /var/log/syslog | tail

# 8) Test before scheduling
# Run the EXACT command as the user, in /bin/sh, with empty env:
sudo -u www-data env -i /bin/sh -c '/opt/myapp/bin/backup.sh'

# 9) Locking — prevent overlapping runs
# Use flock to ensure only one instance runs at a time:
* * * * * /usr/bin/flock -n /tmp/myjob.lock /opt/myapp/bin/poll.sh

# 10) DST gotcha
# Jobs scheduled to run when the clock skips (e.g. 02:30 on DST-forward day) may NOT run.
# Use 'anacron' for jobs that must run even after sleep / power-off / clock changes.

# === systemd timers — modern alternative ===

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

[Service]
Type=oneshot
User=www-data
ExecStart=/opt/myapp/bin/backup.sh
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 02:30

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true          # run on next boot if missed (DST / downtime safe)
RandomizedDelaySec=600    # avoid thundering herd

[Install]
WantedBy=timers.target

# Enable + start
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
sudo systemctl list-timers --all

# Run on demand
sudo systemctl start backup.service

# Logs (centralised, structured)
journalctl -u backup.service
journalctl -u backup.service --since today

# OnCalendar syntax cheat sheet
#   *-*-* 02:30:00          daily at 02:30
#   Mon *-*-* 09:00:00      Monday 09:00
#   *-*-1 04:00:00          1st of month 04:00
#   *-*-* *:00/15           every 15 min
#   *-*-* 09..17:00         hourly between 09:00 and 17:00
#   daily, weekly, monthly  — shortcuts

# Why systemd timers > cron
# - Centralised logs (journalctl)
# - Persistent=true catches missed runs
# - RandomizedDelaySec avoids thundering herd
# - Job description in Unit metadata
# - Resource limits via the .service (CPUQuota, MemoryMax)
# - Dependency ordering with other units (After=postgresql.service)

# === When to use what ===
# Cron               : portable POSIX systems, simple recurring tasks
# systemd timer      : Linux production servers, audit + reliability matter
# Application schedule (Sidekiq cron, Celery beat, Airflow): when job logic is in your app stack
# Cloud scheduler (EventBridge, Cloud Scheduler): serverless

# === Useful tools ===
# crontab.guru        — visual cron expression tester
# anacron             — runs missed jobs on next boot (laptops/desktops)
# fcron               — modern cron with richer scheduling
# at                  — one-off scheduled commands (`at 17:00 tomorrow`)

Why it matters

For new Linux servers, prefer systemd timers — you get journald logs, missed-run recovery, and randomised delays for free. Reach for cron when you need POSIX portability or simplicity.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
crontab -e
# m h dom mon dow command
0 3 * * * /usr/local/bin/backup.sh
Try it Yourself »

Discussion

Loading…