Automation Tools — cron & at¶
cron lets your scripts run themselves — once you write a script, scheduling it to run every night, every hour, or every minute is a one-liner.
Learning Objectives¶
- Schedule recurring jobs with
crontab - Schedule one-time jobs with
at - Understand cron's environment and how it differs from your login shell
- Debug cron jobs that work on the command line but fail when scheduled
- Manage environment variables in automated scripts
cron Basics¶
cron is a daemon that executes scheduled commands. Edit your user's schedule with:
crontab -e # open your crontab for editing
crontab -l # list current crontab
crontab -r # remove your crontab (careful — no confirmation!)
Crontab Format¶
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 7, 0 and 7 are Sunday)
│ │ │ │ │
* * * * * /path/to/command
Common Cron Expressions¶
* * * * * every minute
0 * * * * every hour (at :00)
0 2 * * * every day at 2:00 AM
0 2 * * 0 every Sunday at 2:00 AM
0 2 1 * * first of every month at 2:00 AM
*/15 * * * * every 15 minutes
0 9-17 * * 1-5 every hour from 9 AM to 5 PM, Monday-Friday
crontab.guru
The site crontab.guru lets you type a cron expression and see a plain-English description. Use it to verify your schedule before deploying.
A Real Crontab¶
# Daily backup at 2:30 AM
30 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1
# System health check every 5 minutes
*/5 * * * * /home/user/scripts/health_check.sh
# Weekly cleanup every Sunday at midnight
0 0 * * 0 /home/user/scripts/cleanup.sh >> /var/log/cleanup.log 2>&1
The cron Environment Problem¶
Cron runs with a minimal environment — no ~/.bashrc, no $PATH beyond /usr/bin:/bin. This is the #1 reason cron jobs fail silently.
# Wrong — relies on $PATH
0 2 * * * backup.sh
# Correct — full path
0 2 * * * /home/user/scripts/backup.sh
# Also correct — set PATH in the crontab
PATH=/usr/local/bin:/usr/bin:/bin
0 2 * * * backup.sh
Cron email
By default, cron emails output to the local system user. On most servers there is no local mail, so output disappears. Always redirect output explicitly: command >> /path/to/logfile.log 2>&1.
Debug cron issues by capturing the environment:
at — One-Time Scheduled Commands¶
at 3pm tomorrow # opens interactive prompt
at 14:30 2024-01-20 # specific date and time
echo "/path/to/script.sh" | at 3pm # non-interactive
echo "rm -f /tmp/tempfile" | at now + 1 hour
atq # list pending jobs
atrm 3 # remove job number 3
Systemd Timers (modern alternative)¶
On systemd-based Linux, timers are more powerful than cron:
For production servers, consider systemd timers for better logging and dependency management.
Environment Management¶
direnv¶
# .envrc in project directory — loaded automatically when you cd into it
export DATABASE_URL="postgres://localhost/mydb"
export API_KEY="dev-key-here"
dotfiles pattern¶
# ~/.bash_profile (login shells)
export PATH="$HOME/.local/bin:$PATH"
export EDITOR="vim"
# ~/.bashrc (interactive shells)
alias ll='ls -la'
alias gs='git status'
Practice Exercises¶
Main (write a short script)¶
Create ~/scripts/health_check.sh suitable for running via cron every 5 minutes:
#!/usr/bin/env bash
set -euo pipefail
LOGFILE="/var/log/health_check.log"
THRESHOLD_DISK=85
THRESHOLD_MEM=90
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOGFILE"; }
disk_pct=$(df / | awk 'NR==2 {gsub(/%/,"",$5); print $5}')
mem_pct=$(free | awk '/^Mem:/ {printf "%.0f", $3/$2*100}')
if (( disk_pct > THRESHOLD_DISK )); then
log "ALERT: Disk usage at ${disk_pct}% (threshold: ${THRESHOLD_DISK}%)"
fi
if (( mem_pct > THRESHOLD_MEM )); then
log "ALERT: Memory usage at ${mem_pct}% (threshold: ${THRESHOLD_MEM}%)"
fi
Schedule it: */5 * * * * /home/user/scripts/health_check.sh
Stretch¶
- Write a cron job that runs every weekday at 9 AM and emails you the current disk usage summary. (Use
mailcommand or redirect to a file if no mail is configured.) - Research the difference between
/etc/crontab(system crontab) and user crontabs (crontab -e). What extra field does/etc/crontabhave?
Interview Questions¶
- What is the most common reason a cron job fails when the same command works in the terminal?
Show answer
The $PATH environment variable. Cron runs with a minimal $PATH (/usr/bin:/bin), not your login shell's $PATH. Commands that rely on /usr/local/bin, ~/.local/bin, or other custom paths will not be found. The fix: use full absolute paths in cron jobs, or set PATH explicitly at the top of the crontab.
- What does
*/15mean in the minute field of a crontab?
Show answer
It means "every 15 minutes" — specifically at minutes 0, 15, 30, and 45. The */N syntax means "every N units." So */15 * * * * runs at :00, :15, :30, and :45 past every hour.
- How do you prevent two instances of a cron job from running simultaneously?
Show answer
Use a lock file: exec 9>/tmp/myjob.lock; flock -n 9 || exit 0. Or use flock directly: flock -n /tmp/myjob.lock /path/to/script.sh. If a previous instance is still running when cron fires again, the new instance exits immediately rather than running in parallel.
day03-part2-regular-expressions | day04-part2-networking-apis