{ "id": "cron-jobs", "title": "Cron Jobs & Scheduled Tasks", "category": "sysadmin", "tags": ["cron", "crontab", "schedule", "backup", "automation"], "updated": "2025-12-01", "summary": "Cron syntax, user vs system crons, and common failure modes.", "sections": [ { "heading": "Cron Syntax", "body": "

A crontab entry has five time fields followed by the command:

", "code": "# ┌─── minute (0–59)\n# │ ┌─── hour (0–23)\n# │ │ ┌─── day of month (1–31)\n# │ │ │ ┌─── month (1–12)\n# │ │ │ │ ┌─── day of week (0–7, 0 and 7 are Sunday)\n# │ │ │ │ │\n * * * * * /path/to/command\n\n# Examples:\n0 2 * * * /usr/local/bin/backup.sh # 2am every day\n*/15 * * * * /usr/local/bin/check.sh # every 15 minutes\n0 0 1 * * /usr/local/bin/monthly.sh # midnight on the 1st" }, { "heading": "User Crontabs", "body": "

Each user can have their own crontab. Commands run as that user.

", "code": "crontab -e # edit your crontab\ncrontab -l # list your crontab\ncrontab -l -u alice # list alice's crontab (root only)\ncrontab -r # delete your crontab (dangerous—no confirmation)" }, { "heading": "System Cron Directories", "body": "

Scripts dropped into these directories run at the corresponding interval without needing a crontab entry:

", "code": "/etc/cron.daily/\n/etc/cron.weekly/\n/etc/cron.monthly/\n/etc/cron.hourly/\n\n# Scripts here must be executable and owned by root.\n# They must NOT have a file extension—run-parts ignores files with dots in the name." }, { "heading": "Ownership and the PATH Problem", "body": "

Two common failure modes:

Wrong owner: A cron script in /etc/cron.daily/ must be owned by root. If it is owned by another user, run-parts may skip it.

Missing PATH: Cron does not source .bashrc or .profile. Commands that work interactively may fail in cron because the PATH only contains /usr/bin:/bin. Always use full paths in cron scripts, or set PATH explicitly at the top of the script.

", "code": "#!/bin/bash\nPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n..." }, { "heading": "Checking If a Cron Ran", "body": "", "code": "# Check syslog or the cron-specific log\ngrep CRON /var/log/syslog | tail -20\ncat /var/log/cron.log # if separate cron log is configured\n\n# Check journald\njournalctl -u cron --since \"1 hour ago\"" }, { "heading": "Capturing Cron Output", "body": "

By default, cron mails output to the user. On servers with no mail configured, errors disappear silently. Redirect to a log file instead:

", "code": "0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1" } ] }