Cron & Scheduling
Writing crontab schedules, and the environment/PATH pitfalls that make scripts behave differently under cron than in an interactive shell.
The Crontab Format
* * * * * command
│ │ │ │ │
│ │ │ │ └── day of week (0-6, Sunday=0)
│ │ │ └──── month (1-12)
│ │ └────── day of month (1-31)
│ └──────── hour (0-23)
└────────── minute (0-59)
crontab -e # edit YOUR crontab
crontab -l # list your current crontab entries
crontab -r # remove your entire crontab (careful — no confirmation)
sudo crontab -u deploy -e # edit another user's crontab
Common Schedule Examples
0 2 * * * /opt/scripts/backup.sh # daily at 2:00 AM
*/15 * * * * /opt/scripts/healthcheck.sh # every 15 minutes
0 0 * * 0 /opt/scripts/weekly_report.sh # every Sunday at midnight
0 9-17 * * 1-5 /opt/scripts/business_hours.sh # hourly, 9 AM-5 PM, weekdays only
0 0 1 * * /opt/scripts/monthly_cleanup.sh # 1st of every month
@reboot /opt/scripts/startup.sh # once, at system boot
Why Cron Scripts “Work in the Terminal But Not in Cron”
This is the single most common cron issue. Cron runs jobs with a minimal, non-interactive, non-login shell environment — it does NOT source .bashrc/.bash_profile, and $PATH is typically just /usr/bin:/bin.
# BAD: relies on PATH having picked up nvm/pyenv/custom tool locations
0 2 * * * backup.sh
# GOOD: use absolute paths for the interpreter and every tool the script calls
0 2 * * * /usr/bin/bash /opt/scripts/backup.sh
# GOOD: explicitly set PATH and other environment inside the script itself
#!/usr/bin/env bash
export PATH="/usr/local/bin:/usr/bin:/bin:$PATH"
source /home/deploy/.env
Always Redirect Output — Cron Emails or Silently Drops It
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
Without explicit redirection, cron either emails output to the crontab owner (if mail is configured, which is often not the case on modern servers) or silently discards it — leaving you with no record of failures.
Preventing Overlapping Runs
*/5 * * * * /usr/bin/flock -n /tmp/sync.lock /opt/scripts/sync.sh
flock -n (non-blocking) ensures a new invocation exits immediately if the previous one is still running, rather than stacking up overlapping jobs — critical for tasks that might occasionally run longer than the schedule interval.
systemd Timers: The Modern Alternative
# /etc/systemd/system/backup.timer
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
systemctl list-timers # see all scheduled timers and next run
sudo systemctl enable --now backup.timer
journalctl -u backup.service # logs integrated with the systemd journal, unlike plain cron
Persistent=true catches up a missed run after downtime (e.g., the server was off at 2 AM) — plain cron has no equivalent.
Testing a Cron Script Properly
# Simulate cron's minimal environment before trusting a script will work when scheduled
env -i /usr/bin/bash /opt/scripts/backup.sh
Production Considerations
- Always use absolute paths (for both the interpreter and any tools/binaries the script calls) in cron jobs — never rely on an assumed
$PATH. - Always redirect cron job output explicitly to a log file (
>> log 2>&1) — don’t rely on cron’s mail delivery, which is frequently unconfigured on modern servers. - Prefer systemd timers over cron for new work when the target systems use systemd — better logging integration, dependency support, and
Persistent=truecatch-up semantics.
Quick Interview Answer
“Cron’s five fields are minute, hour, day-of-month, month, day-of-week. The classic cron gotcha is that jobs run with a minimal, non-interactive environment — no
.bashrc, and a bare-bones$PATH— so scripts that work fine interactively often fail under cron unless they use absolute paths and set up their own environment explicitly. Always redirect output to a log file, and useflock -nto prevent overlapping runs of a job that might occasionally run longer than its schedule interval.”
Common Mistakes
- Assuming a cron job has the same
$PATHand environment variables as an interactive shell. - Not redirecting cron job output, leaving no record when something silently fails.
- Scheduling a job frequently enough that overlapping runs are possible, without a lock (
flock) to prevent it.
Add More Questions to This Guide
Know a question that should be here? Share it and help the community!
Open Google Form