Skip to main content

cron

Schedule recurring and one-time tasks using cron, crontab, at, and launchd. Use when the user asks to set up scheduled jobs, configure crontab entries, write cron expressions, schedule one-time tasks with at, create launchd plist files on macOS, debug why a cron job is not running, or manage periodic automated tasks on Unix/Linux/macOS systems.

Source facts

Repository
bug-ops/zeph
Last source activity
March 30, 2026 at 00:01
Detected SKILL.md language
English
Stars
66
Forks
7

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
cron
category
system
description
Schedule recurring and one-time tasks using cron, crontab, at, and launchd. Use when the user asks to set up scheduled jobs, configure crontab entries, write cron expressions, schedule one-time tasks with at, create launchd plist files on macOS, debug why a cron job is not running, or manage periodic automated tasks on Unix/Linux/macOS systems.
license
MIT
compatibility
Requires cron/crontab (Linux/macOS) or launchd (macOS)
metadata
{"author":"zeph","version":"1.0"}
# Task Scheduling with Cron, At, and Launchd ## Cron Expression Format ``` ┌─────────── minute (0-59) │ ┌───────── hour (0-23) │ │ ┌─────── day of month (1-31) │ │ │ ┌───── month (1-12 or JAN-DEC) │ │ │ │ ┌─── day of week (0-6, SUN-SAT; 7 = SUN on some systems) │ │ │ │ │ * * * * * command ``` ### Special Characters | Character | Meaning | Example | |-----------|---------|---------| | `*` | Any value | `* * * * *` (every minute) | | `,` | List | `1,15,30` (at 1, 15, 30) | | `-` | Range | `1-5` (1 through 5) | | `/` | Step | `*/5` (every 5 units) | ### Common Expressions | Expression | Schedule | |------------|----------| | `* * * * *` | Every minute | | `*/5 * * * *` | Every 5 minutes | | `*/15 * * * *` | Every 15 minutes | | `0 * * * *` | Every hour (at :00) | | `0 */2 * * *` | Every 2 hours | | `30 * * * *` | Every hour at :30 | | `0 0 * * *` | Daily at midnight | | `0 6 * * *` | Daily at 6:00 AM | | `0 8,12,18 * * *` | At 8 AM, noon, 6 PM | | `0 9-17 * * *` | Every hour from 9 AM to 5 PM | | `0 0 * * 0` | Weekly on Sunday at midnight | | `0 0 * * 1-5` | Weekdays at midnight | | `0 0 * * 6,0` | Weekends at midnight | | `0 0 1 * *` | First day of every month | | `0 0 1 1 *` | Yearly on January 1 | | `0 0 1 */3 *` | Every 3 months (quarterly) | | `0 0 15 * *` | 15th of every month | | `5 4 * * 0` | Sunday at 4:05 AM | | `0 22 * * 1-5` | Weekdays at 10 PM | ### Predefined Shortcuts | Shortcut | Equivalent | Description | |----------|-----------|-------------| | `@reboot` | — | Run once at startup | | `@yearly` / `@annually` | `0 0 1 1 *` | Once a year (Jan 1) | | `@monthly` | `0 0 1 * *` | Once a month (1st) | | `@weekly` | `0 0 * * 0` | Once a week (Sunday) | | `@daily` / `@midnight` | `0 0 * * *` | Once a day | | `@hourly` | `0 * * * *` | Once an hour | ## Crontab Management ```bash # Edit current user's crontab crontab -e # List current user's crontab crontab -l # Remove current user's crontab (careful!) crontab -r # Edit crontab for another user (requires root) sudo crontab -u username -e # List another user's crontab sudo crontab -u username -l # Create crontab from file crontab mycrontab.txt # Backup crontab crontab -l > crontab-backup.txt # Restore crontab from backup crontab crontab-backup.txt ``` ## Crontab File Format ```bash # Environment variables (set before jobs) SHELL=/bin/bash PATH=/usr/local/bin:/usr/bin:/bin MAILTO=admin@example.com HOME=/home/user # Jobs # min hour dom month dow command # Daily backup at 2:30 AM 30 2 * * * /usr/local/bin/backup.sh # Every 15 minutes: check service health */15 * * * * /usr/local/bin/healthcheck.sh # Weekdays at 9 AM: send report 0 9 * * 1-5 /usr/local/bin/send-report.sh # Monthly cleanup on the 1st at 3 AM 0 3 1 * * /usr/local/bin/cleanup.sh # At reboot: start services @reboot /usr/local/bin/start-services.sh ``` ## Output Handling ```bash # Redirect stdout to file * * * * * /path/to/script.sh > /var/log/cron-output.log 2>&1 # Append to file * * * * * /path/to/script.sh >> /var/log/cron-output.log 2>&1 # Discard all output (silent) * * * * * /path/to/script.sh > /dev/null 2>&1 # Redirect stdout and stderr separately * * * * * /path/to/script.sh > /var/log/cron.log 2> /var/log/cron-error.log # Email output (if MAILTO is set) MAILTO=user@example.com 0 * * * * /path/to/script.sh # Disable email MAILTO="" 0 * * * * /path/to/script.sh # Email only on error 0 * * * * /path/to/script.sh > /dev/null ``` ## Environment in Cron Cron jobs run with a minimal environment. The PATH is usually just `/usr/bin:/bin`. ```bash # Set PATH in crontab PATH=/usr/local/bin:/usr/bin:/bin:/home/user/.local/bin # Or use full paths in commands 0 * * * * /usr/local/bin/python3 /home/user/scripts/task.py # Or source profile in command 0 * * * * . /home/user/.profile && /home/user/scripts/task.sh # Or wrap in bash with login shell 0 * * * * /bin/bash -lc '/home/user/scripts/task.sh' # Set environment variables inline 0 * * * * LANG=en_US.UTF-8 /home/user/scripts/task.sh # Set in crontab file LANG=en_US.UTF-8 NODE_ENV=production ``` ## Locking (Preventing Overlap) ```bash # Using flock (recommended) */5 * * * * flock -n /tmp/myjob.lock /path/to/script.sh # flock with timeout (wait up to 60 seconds for lock) */5 * * * * flock -w 60 /tmp/myjob.lock /path/to/script.sh # Using PID file (manual) */5 * * * * /path/to/script-with-pidcheck.sh # In script: # PIDFILE=/tmp/myjob.pid # if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") 2>/dev/null; then exit 0; fi # echo $$ > "$PIDFILE" # trap "rm -f $PIDFILE" EXIT ``` ## System Cron Directories ```bash # System-wide crontab /etc/crontab # Drop-in directories (scripts placed here run automatically) /etc/cron.d/ # custom cron files (crontab format with user field) /etc/cron.hourly/ # scripts run hourly /etc/cron.daily/ # scripts run daily /etc/cron.weekly/ # scripts run weekly /etc/cron.monthly/ # scripts run monthly # Format in /etc/crontab and /etc/cron.d/* includes a user field: # min hour dom month dow user command */5 * * * * root /usr/local/bin/check.sh ``` ## at — One-Time Scheduled Tasks ```bash # Schedule a command for a specific time echo "/path/to/script.sh" | at 14:30 # Schedule for a specific date and time echo "/path/to/script.sh" | at 14:30 2024-12-25 # Schedule relative to now echo "/path/to/script.sh" | at now + 5 minutes echo "/path/to/script.sh" | at now + 2 hours echo "/path/to/script.sh" | at now + 1 day echo "/path/to/script.sh" | at now + 1 week # Interactive mode (type commands, press Ctrl+D to finish) at 15:00 # > /path/to/script.sh # > echo "Done" | mail user@example.com # > <Ctrl+D> # Other time expressions echo "cmd" | at midnight echo "cmd" | at noon echo "cmd" | at teatime # 4 PM echo "cmd" | at tomorrow echo "cmd" | at "10:00 AM Jul 4" # List pending jobs atq at -l # View job contents at -c JOB_NUMBER # Remove a job atrm JOB_NUMBER at -d JOB_NUMBER # batch — run when system load is low echo "/path/to/heavy-task.sh" | batch ``` ## Launchd (macOS) Launchd is the macOS replacement for cron. Jobs are configured via XML property list (plist) files. ### Plist File Template ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.example.myjob</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/script.sh</string> </array> <!-- Run every 300 seconds (5 minutes) --> <key>StartInterval</key> <integer>300</integer> <!-- OR: calendar-based schedule (like cron) --> <!-- <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>6</integer> <key>Minute</key> <integer>30</integer> </dict> --> <!-- Standard output and error logs --> <key>StandardOutPath</key> <string>/tmp/myjob.stdout.log</string> <key>StandardErrorPath</key> <string>/tmp/myjob.stderr.log</string> <!-- Run at load (startup) --> <key>RunAtLoad</key> <true/> <!-- Environment variables --> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/usr/local/bin:/usr/bin:/bin</string> </dict> </dict> </plist> ``` ### Calendar Schedule Keys ```xml <!-- Daily at 2:30 AM --> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>2</integer> <key>Minute</key> <integer>30</integer> </dict> <!-- Weekdays at 9 AM (Weekday: 1=Mon, 7=Sun) --> <key>StartCalendarInterval</key> <array> <dict> <key>Weekday</key><integer>1</integer> <key>Hour</key><integer>9</integer> <key>Minute</key><integer>0</integer> </dict> <dict> <key>Weekday</key><integer>2</integer> <key>Hour</key><integer>9</integer> <key>Minute</key><integer>0</integer> </dict> <dict> <key>Weekday</key><integer>3</integer> <key>Hour</key><integer>9</integer> <key>Minute</key><integer>0</integer> </dict> <dict> <key>Weekday</key><integer>4</integer> <key>Hour</key><integer>9</integer> <key>Minute</key><integer>0</integer> </dict> <dict> <key>Weekday</key><integer>5</integer> <key>Hour</key><integer>9</integer> <key>Minute</key><integer>0</integer> </dict> </array> <!-- Monthly on the 1st --> <key>StartCalendarInterval</key> <dict> <key>Day</key> <integer>1</integer> <key>Hour</key> <integer>0</integer> <key>Minute</key> <integer>0</integer> </dict> ``` ### Launchd Management ```bash # Load (start) a user agent
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub