Cheatsheets

Cron

Cron

Cron is a time-based job scheduler in Unix/Linux that allows you to run scripts or commands periodically. Essential crontab syntax, scheduling patterns, and management commands.

7 Categories 17 Sections 36 Examples
Cron Crontab Scheduling Job Scheduler Linux Automation

Getting Started

Learn what cron is and understand the basics of job scheduling

What is Cron

Understand cron and its capabilities for job scheduling

Install and verify cron daemon

Install and verify cron daemon is running on the system to enable job scheduling.

Code
Terminal window
# On Debian/Ubuntu
sudo apt-get install cron
# On CentOS/RHEL
sudo yum install cronie
# Start cron daemon
sudo systemctl start cron
# Enable cron to start on boot
sudo systemctl enable cron
# Verify cron is running
sudo systemctl status cron
Execution
Terminal window
systemctl status cron | grep Active
Output
Terminal window
Active: active (running) since Fri 2025-02-28 10:00:00 UTC; 2 days ago
  • Cron is usually pre-installed on Linux systems
  • The daemon must be running for scheduled jobs to execute
  • Use systemctl on modern systems (systemd)
  • On older systems, use service cron start

Basic cron concepts and use cases

Cron executes scheduled scripts and commands automatically according to specified schedules.

Code
Terminal window
# Cron runs in the background as a daemon
# Jobs are stored in crontab (cron table)
# Each user can have their own crontab file
# System-wide cron jobs are stored in /etc/cron.d/
# Cron uses local system time
# Create a simple backup script
cat > backup.sh << 'EOF'
#!/bin/bash
tar -czf /backups/backup-$(date +%Y%m%d).tar.gz /home/user/documents/
EOF
chmod +x backup.sh
# Schedule it to run daily at 2 AM
echo "0 2 * * * /home/user/backup.sh" | crontab -
Execution
Terminal window
crontab -l | head -1
Output
Terminal window
0 2 * * * /home/user/backup.sh
  • Each user has separate crontab access and permissions
  • Root user can schedule system-wide critical tasks
  • Cron jobs inherit the user's environment settings
  • Jobs run in background without user interaction

Cron vs other scheduling methods

Cron is the standard daemon for recurring tasks, complemented by other tools for specific use cases.

Code
Terminal window
# Cron - recurring scheduled jobs (system daemon)
# Good for: regular backups, log rotation, cleanup tasks
echo "0 0 * * * /scripts/daily-cleanup.sh" | crontab -
# At - run job once at specific time (requires atd daemon)
# Good for: one-time future tasks
echo "backup.sh" | at 2:00 AM tomorrow
# Systemd timers - modern alternative to cron
# Good for: system services with dependencies
# Uses .timer and .service files
# Background processes - shell jobs
# Good for: background execution in current session only
./long-running-script.sh &
Execution
Terminal window
which cron
Output
Terminal window
/usr/sbin/cron
  • Cron persists across reboots
  • At command requires atd daemon
  • Systemd timers are modern systemd-based alternative
  • Background processes (&) only run while shell session active

Crontab Basics

Understand crontab structure and how to work with it

View and understand crontab file structure

Crontab displays and manages the cron schedule for the current user.

Code
Terminal window
# View current user's crontab
crontab -l
# View another user's crontab (requires root)
sudo crontab -l -u username
# View system-wide crontab
cat /etc/crontab
# View all cron directories
ls -la /etc/cron.* 2>/dev/null
# Check user crontab files location
ls -la /var/spool/cron/crontabs/
Execution
Terminal window
crontab -l 2>/dev/null || echo "No crontab for current user"
Output
/var/spool/cron/crontabs/username
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:47 vixie Exp $)
0 2 * * * /home/user/backup.sh
  • Each user has their own crontab file in /var/spool/cron/crontabs/
  • System crontabs are in /etc/cron.d/ and /etc/crontab
  • Always use crontab command to edit, not text editor directly
  • crontab -l shows current schedule

Account-specific cron directories

System-wide cron directories allow scheduling tasks for all users without individual crontab management.

Code
Terminal window
# View daily scheduled jobs (run at 6:25 AM)
ls -la /etc/cron.daily/
# View hourly scheduled jobs (run at 17 minutes past each hour)
ls -la /etc/cron.hourly/
# View weekly scheduled jobs
ls -la /etc/cron.weekly/
# View monthly scheduled jobs
ls -la /etc/cron.monthly/
# Add custom script to daily execution
sudo cp myscript.sh /etc/cron.daily/
sudo chmod 755 /etc/cron.daily/myscript.sh
Execution
Terminal window
ls /etc/cron.d/ 2>/dev/null | head -5
Output
Terminal window
anacron
popularity-contest
run-parts
  • Scripts in cron.daily/ run once daily
  • Scripts must be executable (chmod +x)
  • No file extensions needed in cron directories
  • Perfect for system-wide maintenance tasks

Core Concepts

Understand time-based scheduling and cron job execution

Understand cron timing and timezone

Cron uses the system's time zone, so verify correct time zone configuration for accurate scheduling.

Code
Terminal window
# Cron uses system time
# Check system time and timezone
date
timedatectl
cat /etc/timezone
# View system clock
hwclock --show
# Update timezone if needed
sudo timedatectl set-timezone America/New_York
# Important: Change timezone, then update cron times
# Cron doesn't automatically adjust for timezone changes
Execution
Terminal window
date && timedatectl | grep "Time zone"
Output
Terminal window
Fri Feb 28 15:30:45 UTC 2025
Time zone: UTC (UTC, +0000)
  • Cron respects system time zone
  • If system time changes, all future jobs recalculate
  • DST changes don't auto-adjust cron times
  • Use timedatectl or tzconfig to manage time zone

Cron job execution environment

Cron jobs run with limited environment, so always use absolute paths and set variables explicitly.

Code
# Cron job runs with minimal environment
# Create a script to test environment
cat > test-env.sh << 'EOF'
#!/bin/bash
{
echo "=== Cron Job Environment ==="
echo "User: $(whoami)"
echo "Home: $HOME"
echo "Shell: $SHELL"
echo "PATH: $PATH"
echo "PWD: $PWD"
} >> /tmp/cron-env.log
EOF
# Add to crontab
echo "* * * * * /path/to/test-env.sh" | crontab -
# Check log after a minute
cat /tmp/cron-env.log
Execution
Terminal window
echo "Remember: Cron has minimal environment"
Output
Terminal window
Remember: Cron has minimal environment
  • Cron doesn't load shell profile (.bashrc, .bash_profile)
  • Home directory may not be set
  • PATH is set to /usr/bin:/bin
  • Use absolute paths for all scripts and commands
  • Set environment variables at top of crontab if needed

Crontab Syntax

Learn the complete crontab syntax and field descriptions

Field Format and Layout

Understanding the five fields that define cron schedules

Crontab field structure diagram

The crontab uses five time fields followed by the command to execute, with specific value ranges.

Code
# CRON SYNTAX DIAGRAM
Min Hour Day Month Weekday Command
* * * * * /path/to/command
┬ ┬ ┬ ┬ ┬
│ │ │ │ └─ Weekday (0=Sunday, 1=Monday, ..., 6=Saturday)
│ │ │ └────── Month (1=January, 2=February, ..., 12=December)
│ │ └─────────── Day (1-31, specific day of month)
│ └──────────────── Hour (0-23, 24-hour format)
└───────────────────── Minute (0-59, at this minute)
# FIELD RANGES AND ALLOWED VALUES:
Field Range Description
──────────────────────────────────────────
Minute 0-59 Minute of the hour
Hour 0-23 Hour of the day (24-hour format)
Day 1-31 Day of the month
Month 1-12 Month (Jan=1, Dec=12)
Weekday 0-7 Day of week (0 & 7 = Sunday, 6 = Saturday)
Execution
Terminal window
echo "Crontab format: MIN HOUR DAY MONTH WEEKDAY COMMAND"
Output
Terminal window
Crontab format: MIN HOUR DAY MONTH WEEKDAY COMMAND
  • All fields are space-separated
  • Asterisk (*) means "any value"
  • Fields can contain numbers, ranges, lists, or special operators
  • Whitespace must separate each field and command

Common field values reference

Common field values help you understand and construct cron schedules quickly.

Code
Terminal window
# MINUTE (0-59)
0 - At minute 0 (top of hour)
15 - At minute 15 (quarter past)
*/5 - Every 5 minutes
0,30 - At minutes 0 and 30 (twice per hour)
# HOUR (0-23)
0 - At midnight (12 AM)
12 - At noon (12 PM)
13 - At 1 PM
*/4 - Every 4 hours
9-17 - Business hours (9 AM to 5 PM)
# DAY (1-31)
1 - First day of month
15 - Fifteenth day of month
*/2 - Every 2 days
1-7 - First week of month
# MONTH (1-12)
1 - January
12 - December
*/3 - Every 3 months (Jan, Apr, Jul, Oct)
6-8 - June, July, August (summer)
# WEEKDAY (0-7, where 0 and 7 = Sunday)
0 - Sunday
1 - Monday
5 - Friday
6 - Saturday
1-5 - Monday through Friday (weekdays)
Execution
Terminal window
crontab -l | grep "^[^#]" | head -1 || echo "No scheduled jobs"
Output
Terminal window
No scheduled jobs
  • Remember AM/PM: hours 0-23 (0=midnight, 12=noon, 23=11PM)
  • Days and months are 1-based (not 0-based like programming)
  • Weekday: 0 and 7 both represent Sunday

Operators and Syntax

Master cron operators for flexible scheduling patterns

Cron operators reference

Cron operators allow flexible scheduling patterns using standard mathematical and listing syntax.

Code
# CRON OPERATORS
OPERATOR | MEANING | EXAMPLE | EXPLANATION
──────────┼────────────────────┼──────────────────────┼──────────────────────────
* | Any value | * * * * * | Every minute of every day
, | Value separator | 0,30 * * * * | At 0 and 30 minutes (twice hourly)
- | Range of values | 9-17 * * * * | Every minute from 9 AM to 5 PM
/ | Step values | */15 * * * * | Every 15 minutes
L | Last | L * * * | Last day of month (some systems)
W | Weekday | 15W * * * | Nearest weekday to 15th (some systems)
# | Nth occurrence | * * * * 1#2 | Second Monday (some systems)
# IMPORTANT NOTES:
- L and W operators are NOT standard POSIX cron
- They may only work in some cron implementations
- Stick to *, , , -, / operators for portability
Execution
Terminal window
echo "Standard operators: * , - /"
Output
Terminal window
Standard operators: * , - /
  • Always use standard operators (* , - /) for maximum compatibility
  • Values in ranges and lists must be valid for the field
  • Spaces not allowed within field values (no spaces around , or -)

Practical operator examples

Combinations of operators create complex but precise scheduling patterns for real-world needs.

Code
Terminal window
# ASTERISK (*) - Match any value
0 * * * * # Every hour at minute 0
* * * * * # Every minute of every day
# COMMA (,) - List specific values
0 8,12,17 * * * # At 8 AM, 12 PM (noon), and 5 PM
0 0 1,15 * * # First and 15th day of month at midnight
0 0 * * 0,6 # Sunday and Saturday at midnight
# DASH (-) - Range of values
0 9-17 * * * # Every hour from 9 AM to 5 PM
30 9-17 * * 1-5 # 30 minutes past hour, 9 AM-5 PM, Mon-Fri
0 0 1-7 * * # First week of month at midnight
# SLASH (/) - Step values / intervals
*/30 * * * * # Every 30 minutes
*/5 9-17 * * * # Every 5 minutes during business hours
0 */6 * * * # Every 6 hours starting at midnight
0 0 * * */2 # Every 2 days starting from Sunday
# COMBINATIONS
*/15 9-17 * * 1-5 # Every 15 min, 9-5pm, weekdays
0 8-18 * * 1-5 # Every hour 8-6pm, Mon-Fri
Execution
Terminal window
echo "0 9-17 * * 1-5 /path/to/script.sh" | crontab -
  • Steps (/) count from the field's minimum value
  • */5 in minutes = every 5 minutes (0, 5, 10, 15, ...)
  • 5-55/5 in minutes = 5, 10, 15, 20, ..., 55

Syntax Validation and Examples

Validate your crontab syntax and learn from examples

Validate crontab syntax before installing

Always validate syntax before installing crontabs to prevent silent job failures.

Code
Terminal window
# Method 1: Use crontab with -i flag to test
crontab -e # Opens editor, validates on save
# Method 2: Write to temp file, then test
cat > new_cron.txt << 'EOF'
0 2 * * * /usr/local/bin/backup.sh
0 0 * * 0 /usr/local/bin/weekly-report.sh
EOF
# Method 3: Online cron expression tester
# Visit: https://crontab.guru/
# Paste expression and see explanation
# Method 4: Manual validation checklist
# - Check all 5 fields present (space-separated)
# - Minute: 0-59, Hour: 0-23, Day: 1-31
# - Month: 1-12, Weekday: 0-7 (0 and 7 = Sunday)
# - Use only valid operators: * , - /
# - No invalid value combinations
# Install validated crontab
crontab new_cron.txt
Execution
Terminal window
echo "0 2 * * * /home/user/backup.sh" | grep -E "^[0-9,*/-]+ [0-9,*/-]+ [0-9,*/-]+ [0-9,*/-]+ [0-9,*/-]+"
Output
Terminal window
0 2 * * * /home/user/backup.sh
  • Invalid crontab syntax won't raise errors in some systems
  • Use crontab -e in editor mode for immediate validation feedback
  • crontab.guru is excellent for visualizing schedules

Full examples with explanations

Complete examples cover most common scheduling needs and can be adapted for your use cases.

Code
Terminal window
# Run every minute (test only!)
* * * * * /path/to/command
# Run every hour at minute 0 (top of hour)
0 * * * * /path/to/command
# Run every 15 minutes
*/15 * * * * /path/to/command
# Run at 2 AM every day
0 2 * * * /path/to/backup.sh
# Run at 2:30 AM every day
30 2 * * * /path/to/backup.sh
# Run every 6 hours (midnight, 6am, noon, 6pm)
0 */6 * * * /path/to/maintenance.sh
# Run at 9 AM and 5 PM, Monday to Friday
0 9,17 * * 1-5 /path/to/report.sh
# Run on the 1st and 15th day of every month at midnight
0 0 1,15 * * /path/to/billing.sh
# Run every Sunday at 3 AM
0 3 * * 0 /path/to/weekly-task.sh
# Run every other hour on weekdays
0 */2 * * 1-5 /path/to/frequent-job.sh
# Run at 10, 20, 30, 40, 50 minutes every hour
10,20,30,40,50 * * * * /path/to/command
Execution
Terminal window
echo "Examples loaded - use crontab.guru to visualize"
Output
Terminal window
Examples loaded - use crontab.guru to visualize
  • Always test script manually before scheduling
  • Use absolute paths for all commands
  • Redirect output to log files for monitoring
  • Document all scheduled jobs in crontab

Special Strings

Use predefined scheduling shortcuts for common intervals

'@' Symbols (At Strings)

Special shortcuts for commonly used scheduling intervals

Special string reference and usage

Special strings provide readable shortcuts for standard scheduling patterns.

Code
# SPECIAL @ STRINGS - Shortcuts for Common Schedules
SPECIAL STRING | EQUIVALENT CRON | DESCRIPTION
────────────────┼───────────────────┼─────────────────────────────────
@reboot | N/A | Run once, at startup (reboot)
@hourly | 0 * * * * | Run once every hour at minute 0
@daily | 0 0 * * * | Run once every day at midnight
@midnight | 0 0 * * * | Run once at midnight (same as @daily)
@weekly | 0 0 * * 0 | Run once weekly on Sunday at midnight
@monthly | 0 0 1 * * | Run once monthly on 1st day at midnight
@yearly | 0 0 1 1 * | Run once yearly on Jan 1st at midnight
@annually | 0 0 1 1 * | Alias for @yearly
# ADVANTAGES OF SPECIAL STRINGS:
- More readable than cron time expressions
- Less prone to syntax errors
- Perfect for standard scheduling intervals
- Supported by all modern cron implementations
Execution
Terminal window
echo "@daily /home/user/backup.sh" | crontab -
  • @reboot runs at system startup (not a specific time)
  • @midnight and @daily are equivalent
  • All other @strings have specific times (see equivalent column)

Using special strings in crontab

Special strings make crontab files more maintainable and easier to understand.

Code
Terminal window
# Create crontab with special strings
cat > cron_schedule.txt << 'EOF'
# System maintenance tasks
@reboot /usr/local/bin/system-init.sh
# Log rotation (every hour)
@hourly /usr/sbin/logrotate /etc/logrotate.conf
# Database backup (daily at midnight)
@daily /home/user/backup-database.sh
# Weekly report (Sunday at midnight)
@weekly /home/user/generate-report.sh
# Monthly archive (1st of month at midnight)
@monthly /home/user/archive-old-files.sh
# Yearly audit (Jan 1st at midnight)
@yearly /home/user/annual-audit.sh
EOF
# Install the crontab
crontab cron_schedule.txt
# Verify installation
crontab -l
Execution
Terminal window
crontab -l 2>/dev/null | grep "@" | head -3
Output
Terminal window
@reboot /usr/local/bin/system-init.sh
@hourly /usr/sbin/logrotate /etc/logrotate.conf
@daily /home/user/backup-database.sh
  • Mix special strings and normal cron syntax in same crontab
  • Special strings are more readable for standard intervals
  • Use regular cron syntax for non-standard schedules

Special Variables and Environment

Set environment variables and use predefined variables in crontab

Set environment variables in crontab

Environment variables must be set in crontab since cron doesn't load shell profiles.

Code
Terminal window
# Setting variables in crontab file
cat > crontab_with_env.txt << 'EOF'
# Environment variables for all jobs in this crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/username
LOGNAME=username
MAILTO=admin@example.com
# Optional: disable mail on successful execution
# CRONENV=prod
# Now define jobs that use these variables
0 2 * * * /home/username/scripts/backup.sh >> $HOME/logs/backup.log 2>&1
# Or with explicit paths
@daily /usr/local/bin/cleanup.sh >> /home/username/cron.log 2>&1
EOF
# Install crontab
crontab crontab_with_env.txt
# View installed crontab
crontab -l
Execution
Terminal window
echo "Variables set at top of crontab file"
Output
Terminal window
Variables set at top of crontab file
  • Set variables at the top of crontab file
  • MAILTO controls email notifications (set empty to disable)
  • HOME and PATH are especially important
  • SHELL specifies which shell to use (/bin/bash, not /bin/sh)

Common environment gotchas and solutions

Testing with minimal environment reveals issues that will occur in cron jobs.

Code
Terminal window
# GOTCHA 1: PATH not set correctly
# This FAILS - command not found
* * * * * mycommand
# This WORKS - absolute path
* * * * * /usr/bin/mycommand
# Or set PATH at top of crontab
PATH=/usr/local/bin:/usr/bin:/bin
* * * * * mycommand
# GOTCHA 2: HOME directory not set
# This FAILS if script uses ~
* * * * * ~/scripts/backup.sh
# This WORKS - explicit path
* * * * * /home/username/scripts/backup.sh
# Or set HOME in crontab
HOME=/home/username
* * * * * ~/scripts/backup.sh
# GOTCHA 3: Environment variables from .bashrc not loaded
# This FAILS - NO_COLOR not set
* * * * * /usr/bin/command
# This WORKS - source .bashrc first
* * * * * source ~/.bashrc; /usr/bin/command
# Better: set needed variables in crontab
NO_COLOR=1
* * * * * /usr/bin/command
Execution
Terminal window
echo "Always test with: env -i bash -c 'your command'"
Output
Terminal window
Always test with: env -i bash -c 'your command'
  • Test cron jobs with: env -i bash -c 'your script'
  • This simulates minimal cron environment
  • Or use: /usr/bin/env -L bash -c 'your script'
  • Always use absolute paths and set necessary variables

Scheduling Patterns

Real-world scheduling patterns and examples

Common Scheduling Patterns

Practical patterns for typical system administration tasks

Business hours and working day schedules

Business schedule patterns align jobs with working hours.

Code
Terminal window
# Run during business hours (9 AM to 5 PM, Monday-Friday)
0 9-17 * * 1-5 /path/to/business-task.sh
# Run at start of business day (9 AM, weekdays)
0 9 * * 1-5 /path/to/daily-standup.sh
# Run at end of business day (5 PM, weekdays)
0 17 * * 1-5 /path/to/eod-report.sh
# Run every 2 hours during business hours
0 9,11,13,15,17 * * 1-5 /path/to/interim-check.sh
# Run every 30 minutes during business hours
*/30 9-17 * * 1-5 /path/to/frequent-task.sh
# Run weekday evenings (6 PM - 11 PM)
0 18-23 * * 1-5 /path/to/evening-task.sh
# Run weekend task (Saturday and Sunday)
0 10 * * 0,6 /path/to/weekend-task.sh
Execution
Terminal window
echo "0 9-17 * * 1-5 command" | crontab -
  • Hour 9-17 means 9 AM through 5 PM
  • 1-5 for Monday through Friday
  • 0,6 for Saturday and Sunday
  • Adjust based on actual working hours and time zone

Backup and maintenance schedules

Backup schedules should stagger to avoid resource contention and database locks.

Code
Terminal window
# Full backup every Sunday at 2 AM
0 2 * * 0 /path/to/full-backup.sh
# Incremental backup daily at 3 AM
0 3 * * * /path/to/incremental-backup.sh
# Database backup every 6 hours
0 */6 * * * /path/to/db-backup.sh
# Log rotation daily at midnight
0 0 * * * /usr/sbin/logrotate /etc/logrotate.conf
# Weekly maintenance (Sunday 4 AM)
0 4 * * 0 /path/to/weekly-maintenance.sh
# Monthly housekeeping (1st of month, 1 AM)
0 1 1 * * /path/to/monthly-cleanup.sh
# Quarterly archive (Jan 1, Apr 1, Jul 1, Oct 1 at 2 AM)
0 2 1 1,4,7,10 * /path/to/quarterly-archive.sh
# Yearly audit (Jan 1 at 3 AM)
0 3 1 1 * /path/to/annual-audit.sh
Execution
Terminal window
echo "0 2 * * 0 /path/to/backup.sh" | crontab -
  • Schedule backups during low-usage hours
  • Incremental backups can be more frequent than full backups
  • Rotate old backups to manage storage
  • Monitor backup success with logging and alerts

Monitoring and notification schedules

Monitoring jobs run frequently but should be optimized to minimize overhead.

Code
Terminal window
# Health check every 5 minutes
*/5 * * * * /path/to/health-check.sh
# Monitor system every 10 minutes (all day)
*/10 * * * * /path/to/system-monitor.sh
# Check disk space every hour
0 * * * * /path/to/check-disk.sh
# Send daily report at 9 AM (weekdays)
0 9 * * 1-5 /path/to/daily-report.sh | mail -s "Daily Report" admin@example.com
# Weekly status report (Monday 8 AM)
0 8 * * 1 /path/to/weekly-status.sh | mail -s "Weekly Status" team@example.com
# Monitor critical service (every 15 minutes, 24/7)
*/15 * * * * /path/to/critical-service-check.sh
# Alert on failures (every 30 minutes if previous check failed)
*/30 * * * * if [ -f /tmp/service-down ]; then /path/to/alert.sh; fi
Execution
Terminal window
echo "*/5 * * * * /path/to/check.sh" | crontab -
  • Balance frequency with resource usage
  • Use lock files to prevent overlapping runs
  • Log all monitoring results
  • Set alerts for critical failures

Advanced Scheduling Patterns

Complex scheduling for specific needs

Staggered and load-balanced schedules

Staggered patterns distribute resource-intensive tasks across time to maintain system performance.

Code
Terminal window
# Stagger backups across multiple servers
# Server 1: runs at :00
0 2 * * * /path/to/backup.sh
# Server 2: runs at :15
15 2 * * * /path/to/backup.sh
# Server 3: runs at :30
30 2 * * * /path/to/backup.sh
# Server 4: runs at :45
45 2 * * * /path/to/backup.sh
# Load balanced hourly jobs (4 servers, evenly distributed)
# Server 1: run at :00
0 * * * * /path/to/hourly-job.sh
# Server 2: run at :15
15 * * * * /path/to/hourly-job.sh
# Server 3: run at :30
30 * * * * /path/to/hourly-job.sh
# Server 4: run at :45
45 * * * * /path/to/hourly-job.sh
# Rotate tasks across different times
# Task A: Monday, Wednesday, Friday
0 2 * * 1,3,5 /path/to/task-a.sh
# Task B: Tuesday, Thursday
0 2 * * 2,4 /path/to/task-b.sh
# Task C: Sunday and Saturday
0 2 * * 0,6 /path/to/task-c.sh
Execution
Terminal window
echo "Staggered schedules prevent resource bottlenecks"
Output
Terminal window
Staggered schedules prevent resource bottlenecks
  • Stagger when running same task on multiple servers
  • Distribute load across minutes if possible
  • Consider time zone differences across servers
  • Monitor system resources during peak schedule times

Conditional and wrapper-based scheduling

Conditional patterns add robustness and prevent cascading failures.

Code
Terminal window
# Run only if previous job completed (using lock file)
*/5 * * * * [ ! -f /tmp/long-job.lock ] && /path/to/frequent-job.sh
# Run with fallback if primary command fails
0 2 * * * /path/to/primary-backup.sh || /path/to/fallback-backup.sh
# Run with dependency check
0 * * * * [ -x /usr/bin/rsync ] && /path/to/rsync-backup.sh
# Run only on specific conditions (e.g., low load)
*/10 * * * * [ $(uptime | awk -F'average:' '{print $2}' | awk '{print $1}' | cut -d. -f1) -lt 2 ] && /path/to/async-task.sh
# Run with timeout to prevent hanging
0 2 * * * timeout 300 /path/to/backup.sh || echo "Backup timed out!"
# Run with retry logic (wrapper script)
0 * * * * /path/to/retry-wrapper.sh 3 /path/to/unreliable-command.sh
# Run with output capture and error handling
0 2 * * * {
/path/to/backup.sh 2>&1
[ $? -eq 0 ] && echo "Success" || echo "Failed" | mail -s "Backup Error" admin@example.com
}
Execution
Terminal window
echo "[ ! -f /tmp/lock ] && /path/to/command.sh"
  • Use lock files to prevent overlapping executions
  • Always capture errors and log results
  • Use timeout for commands that might hang
  • Test complex schedules thoroughly before deployment

Crontab Management

Edit, view, backup, and manage crontab files

Editing and Installing Crontabs

Methods to safely edit and install crontab files

Edit crontab using the interactive editor

The -e flag opens an interactive editor with validation on save for safe editing.

Code
Terminal window
# Edit current user's crontab
crontab -e
# Edit another user's crontab (requires root)
sudo crontab -e -u username
# Specify which editor to use
EDITOR=vim crontab -e
EDITOR=nano crontab -e
EDITOR=emacs crontab -e
# Change default editor permanently
export EDITOR=vim
echo 'export EDITOR=vim' >> ~/.bashrc
# View crontab before saving (in editor)
# Editor opens temp file - make changes and save
# Cron validates syntax when file is saved
# If syntax is invalid, you'll be asked to re-edit or discard
# Backup current crontab before editing
crontab -l > crontab.backup
crontab -e # Make changes safely
Execution
Terminal window
echo "crontab -e to edit interactively"
Output
Terminal window
crontab -e to edit interactively
  • crontab -e is the recommended method (validates syntax)
  • Default editor determined by EDITOR or VISUAL env var
  • Any syntax errors prevent installation
  • Always backup before making changes

Install crontab from file

Install crontab files for programmatic configuration and automation.

Code
Terminal window
# Create a crontab file
cat > my_crontab << 'EOF'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
HOME=/home/user
# Example jobs
0 2 * * * /home/user/backup.sh
0 0 * * 0 /home/user/weekly-task.sh
EOF
# Install it as current user's crontab
crontab my_crontab
# Install for another user (requires root)
sudo crontab -u username my_crontab
# Replace existing crontab
crontab my_crontab # This overwrites current crontab
# Add to existing crontab (append instead of replace)
crontab -l > current_crontab.txt
cat additional_jobs.txt >> current_crontab.txt
crontab current_crontab.txt
# Verify installation
crontab -l
Execution
Terminal window
echo "0 2 * * * /path/to/job.sh" > cron.txt && crontab cron.txt
  • crontab <file> replaces entire crontab
  • crontab is read entirely before installation
  • Syntax errors prevent installation completely
  • Always backup before installing new crontab

List, Delete, and Manage Crontabs

View and remove scheduled jobs

View and manage crontab entries

List commands show scheduled jobs without opening editor.

Code
Terminal window
# List current user's crontab
crontab -l
# List another user's crontab (requires root)
sudo crontab -l -u username
# Count number of cron jobs
crontab -l | grep -c "^[^#]"
# List non-comment lines only
crontab -l | grep "^[^#]"
# Find specific job
crontab -l | grep "backup"
# List all system crontabs
sudo cat /etc/crontab
# List all user crontabs in /var/spool/cron
sudo ls -la /var/spool/cron/crontabs/
# View specific user's crontab file
sudo cat /var/spool/cron/crontabs/username
Execution
Terminal window
crontab -l 2>/dev/null | head -5
Output
Terminal window
# Comments start with #
0 2 * * * /home/user/backup.sh
  • crontab -l shows current user's crontab
  • grep filters output to show specific jobs
  • Lines starting with
  • System-wide crontabs are in /etc/cron.d/ and /etc/crontab

Delete and remove crontabs

Safe removal techniques preserve other jobs while removing only what's needed.

Code
Terminal window
# DANGER: Remove entire crontab for current user
crontab -r
# DANGER: Remove entire crontab for specific user (requires root)
sudo crontab -r -u username
# Safe way: backup first, then remove
crontab -l > crontab.backup
crontab -r
# Remove specific job without deleting all jobs
crontab -l | grep -v "pattern-to-remove" | crontab -
# Example: remove backup job, keep others
crontab -l | grep -v "backup" | crontab -
# Remove all jobs but keep environment variables
crontab -l | grep "^[A-Z]" | crontab -
# Disable job by commenting it (safer than deleting)
crontab -e # Then add # at start of line
# Remove from system-wide cron
sudo rm /etc/cron.d/jobname
sudo rm /etc/cron.daily/myscript
Execution
Terminal window
crontab -l | grep -v "backup" | crontab -
  • Always backup before removing with crontab -r
  • Use grep to filter and remove specific jobs safely
  • Commenting is safer than deleting for temporary disabling
  • System crontabs require root access to modify

Advanced Crontab Techniques

Backup, restore, and automate crontab management

Backup and restore crontabs

Backup and version control ensure safe crontab management and recovery.

Code
Terminal window
# Backup current crontab before changes
crontab -l > ~/crontab.backup.$(date +%Y%m%d)
# Backup all user crontabs (requires root)
sudo for user in $(cut -f1 -d: /etc/passwd); do
crontab -l -u "$user" > /backups/crontab_$user.backup 2>/dev/null
done
# Restore from backup
crontab ~/crontab.backup.20250228
# Compare current with backup
diff <(crontab -l) <(cat ~/crontab.backup.20250228)
# Version control crontab
crontab -l > crontab.txt
git add crontab.txt
git commit -m "Update crontab: add daily backup job"
# Deploy crontab from version control
git pull
crontab crontab.txt
Execution
Terminal window
crontab -l > crontab.backup.$(date +%Y%m%d)
  • Timestamp backups with date for tracking changes
  • Keep backups in version control for history
  • Test restored crontabs before deploying to production
  • Document all changes in commit messages

Script jobs with logging and error handling

Robust scripts include logging, error handling, and notifications for production reliability.

Code
# Create robust cron script with logging
cat > /usr/local/bin/cron-backup.sh << 'EOF'
#!/bin/bash
set -e # Exit on error
# Configuration
BACKUP_DIR="/backups"
LOG_FILE="/var/log/backup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
HOSTNAME=$(hostname)
# Log function
log() {
echo "[${DATE}] ${HOSTNAME}: $1" >> "${LOG_FILE}"
}
# Error handling
error_exit() {
log "ERROR: $1"
echo "ERROR: $1" | mail -s "Backup Failed on ${HOSTNAME}" admin@example.com
exit 1
}
# Create backup
log "Starting backup..."
tar -czf "${BACKUP_DIR}/backup-$(date +%Y%m%d).tar.gz" /home || error_exit "Backup failed"
log "Backup completed successfully"
# Cleanup old backups (keep 7 days)
find "${BACKUP_DIR}" -name "backup-*.tar.gz" -mtime +7 -delete
log "Cleanup completed"
EOF
chmod +x /usr/local/bin/cron-backup.sh
# Add to crontab with logging
crontab -e
# Add: 0 2 * * * /usr/local/bin/cron-backup.sh >> /var/log/cron.log 2>&1
Execution
Terminal window
chmod +x /usr/local/bin/cron-backup.sh
  • Always include error handling (set -e, exit codes)
  • Log to file for auditing and debugging
  • Send error notifications to admin
  • Use absolute paths for all commands
  • Test scripts thoroughly before scheduling

Advanced Scheduling

Advanced cron features and optimization techniques

Ranges, Steps, and Lists

Master complex scheduling with ranges, steps, and value lists

Using ranges and step values

Ranges and steps create flexible scheduling patterns for complex intervals.

Code
# RANGES (using -)
# Run every minute from 9 AM to 5 PM
* 9-17 * * * /path/to/command
# Run on weekdays (Monday-Friday)
0 0 * * 1-5 /path/to/command
# Run first 7 days of each month
0 0 1-7 * * /path/to/command
# Run June, July, August only
0 0 * 6-8 * /path/to/command
# STEPS/INTERVALS (using /)
# Every 5 minutes
*/5 * * * * /path/to/command
# Every 2 hours
0 */2 * * * /path/to/command
# Every 3 days
0 0 */3 * * /path/to/command
# Every second month (Jan, Mar, May, Jul, Sep, Nov)
0 0 1 */2 * /path/to/command
# Every 15 minutes between 9-17 (9:00, 9:15, 9:30, ..., 17:00)
*/15 9-17 * * * /path/to/command
# Every 4 hours starting at 2 AM (2, 6, 10, 14, 18, 22)
0 2-23/4 * * * /path/to/command
# STEP WITH RANGE
# Start at minute 10, every 15 minutes (10, 25, 40, 55)
10-59/15 * * * * /path/to/command
# Start at hour 8, every 3 hours (8, 11, 14, 17, 20, 23)
0 8-23/3 * * * /path/to/command
# Every 2 days starting from day 1 (1, 3, 5, 7, ...)
0 0 1-31/2 * * /path/to/command
Execution
Terminal window
echo "*/5 * * * * = every 5 minutes"
Output
Terminal window
*/5 * * * * = every 5 minutes
  • Ranges use hyphen: min-max
  • Steps use slash: */interval or min-max/interval
  • Steps count from field minimum (minutes from 0)
  • Ranges and steps can combine in one field

Using lists and comma-separated values

Lists (comma-separated values) specify exact times and dates for flexible scheduling.

Code
Terminal window
# RUN AT SPECIFIC HOURS
# Run at 8 AM, 12 PM (noon), and 5 PM
0 8,12,17 * * * /path/to/command
# Run at 6 AM and 6 PM
0 6,18 * * * /path/to/command
# Run at :00, :15, :30, :45 (every 15 minutes)
0,15,30,45 * * * * /path/to/command
# RUN ON SPECIFIC DAYS OF WEEK
# Run Monday, Wednesday, Friday
0 0 * * 1,3,5 /path/to/command
# Run Saturday, Sunday, Monday
0 0 * * 6,0,1 /path/to/command
# RUN ON SPECIFIC DATES
# Run on 1st, 10th, 20th of month
0 0 1,10,20 * * /path/to/command
# Run on 15th and last day of month (1st of next)
# Note: This is tricky - need separate job for last day
0 0 15 * * /path/to/command
0 0 1 * * [ "$(date +\%d)" != "01" ] && /path/to/command
# RUN IN SPECIFIC MONTHS
# Run in January, April, July, October
0 0 1 1,4,7,10 * /path/to/command
# Run in summer (June, July, August)
0 0 * 6,7,8 * /path/to/command
# COMBINED LISTS AND RANGES
# Run on specific hours and specific days
0 8,14,20 * * 1-5 /path/to/command
# Run at multiple times on multiple days
0,30 9,12,15 * * 1-5 /path/to/command
Execution
Terminal window
echo "0 8,12,17 * * * /path/to/command"
Output
Terminal window
0 8,12,17 * * * /path/to/command
  • Separators are commas with no spaces
  • List all values individually: 1,2,3 (not 1-3 in list form)
  • Can combine lists with ranges: 1,3-5,7 (equals 1,3,4,5,7)
  • Lists work for all fields: minutes, hours, days, months, weekdays

Environment and Optimization

Environment variables, best practices, and performance optimization

Set comprehensive environment in crontab

Proper environment setup ensures scripts work correctly in cron's limited environment.

Code
Terminal window
# COMPLETE CRONTAB WITH ENVIRONMENT SETUP
cat > crontab_optimized << 'EOF'
# ============================================
# ENVIRONMENT CONFIGURATION
# ============================================
# Shell to use (bash, not sh)
SHELL=/bin/bash
BASH_ENV=/home/username/.bashrc
# PATH (critical for command discovery)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Home directory (some scripts use~)
HOME=/home/username
# Current user
LOGNAME=username
USER=username
# Mail configuration (empty = no mail, valid email = send notifications)
MAILTO=admin@example.com
# Language and locale
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
# Optional: Application-specific variables
APP_ENV=production
NODE_ENV=production
DEBUG=0
# ============================================
# SCHEDULED JOBS
# ============================================
# System maintenance
@reboot /usr/local/bin/system-init.sh >> /var/log/cron-init.log 2>&1
# Backups
0 2 * * * /home/username/scripts/backup.sh >> /var/log/backup.log 2>&1
# Database maintenance
0 3 * * 0 /home/username/scripts/db-maintenance.sh >> /var/log/db-maint.log 2>&1
# Log rotation
0 0 * * * /usr/sbin/logrotate /etc/logrotate.conf >> /var/log/logrotate.log 2>&1
EOF
crontab crontab_optimized
Execution
Terminal window
echo "SHELL=/bin/bash PATH=... HOME=..."
Output
Terminal window
SHELL=/bin/bash PATH=... HOME=...
  • Set variables at top of crontab file
  • SHELL should be /bin/bash, not /bin/sh
  • PATH is critical - include all directories where commands exist
  • MAILTO controls email notifications

Performance optimization and load management

Optimization prevents system load spikes and ensures consistent performance.

Code
Terminal window
# PERFORMANCE CONSIDERATIONS
# 1. Stagger resource-intensive jobs
# Don't run everything at midnight
0 1 * * * /path/to/job1.sh # 1 AM
0 2 * * * /path/to/job2.sh # 2 AM
0 3 * * * /path/to/job3.sh # 3 AM
0 4 * * * /path/to/job4.sh # 4 AM
# 2. Add random delay for distributed jobs
# Useful when same job runs on many servers
0 2 * * * sleep $((RANDOM \% 600)) && /path/to/backup.sh
# 3. Limit job concurrency with lock files
# Use wrapper script to prevent overlapping
*/5 * * * * /path/to/locked-job-wrapper.sh /path/to/actual-job.sh
# 4. Use -nice to lower priority for background jobs
0 2 * * * nice -n 19 /path/to/low-priority-job.sh
# 5. Monitor system before running expensive tasks
*/10 * * * * [ $(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | cut -d. -f1) -lt 8 ] && /path/to/compute-intensive.sh
# 6. Redirect output to avoid mail daemon overhead
0 2 * * * /path/to/job.sh > /dev/null 2>&1 # Discard output
0 2 * * * /path/to/job.sh >> /var/log/jobs.log 2>&1 # Log to file
# 7. Break large jobs into smaller pieces
# Process in batches instead of all at once
0 2 * * * /path/to/process-batch.sh 1
0 3 * * * /path/to/process-batch.sh 2
0 4 * * * /path/to/process-batch.sh 3
Execution
Terminal window
echo "Stagger jobs to prevent resource bottlenecks"
Output
Terminal window
Stagger jobs to prevent resource bottlenecks
  • Stagger heavy workloads across multiple hours
  • Monitor system load before running resource-intensive jobs
  • Limit concurrency with lock files to prevent overlapping
  • Use nice for background tasks
  • Log output to files instead of relying on mail

Tips & Troubleshooting

Best practices, common issues, and debugging cron jobs

Best Practices

Essential practices for reliable cron job scheduling

Production-ready cron job checklist

Following best practices ensures reliable job execution and easier debugging.

Code
Terminal window
# PRODUCTION CRON JOB REQUIREMENTS CHECKLIST
# ✓ 1. Use absolute paths for all commands
# BAD:
* * * * * backup.sh
# GOOD:
* * * * * /usr/local/bin/backup.sh
# ✓ 2. Set working directory explicitly
* * * * * cd /home/user && /usr/local/bin/backup.sh
# OR
* * * * * /usr/local/bin/backup.sh -d /var/data
# ✓ 3. Log output to files (not relying on mail)
# BAD:
0 2 * * * /path/to/backup.sh
# GOOD:
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1
# ✓ 4. Capture exit codes for debugging
# GOOD:
0 2 * * * {
/path/to/backup.sh
EXIT_CODE=$?
echo "Backup completed with exit code: $EXIT_CODE" >> /var/log/backup.log
[ $EXIT_CODE -ne 0 ] && echo "Backup failed!" | mail -s "Alert" admin@example.com
} 2>&1 | tee -a /var/log/backup.log
# ✓ 5. Include timestamp in logs
# BAD:
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1
# GOOD:
0 2 * * * echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting backup" >> /var/log/backup.log && /path/to/backup.sh >> /var/log/backup.log 2>&1
# ✓ 6. Protect against overlapping runs
# Use lock file pattern:
*/5 * * * * /path/to/locked-wrapper.sh /path/to/actual-job.sh
# ✓ 7. Document all cron jobs in crontab
# GOOD crontab:
# Daily backup at 2 AM
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1
# Weekly report (Sunday, 8 AM)
0 8 * * 0 /path/to/weekly-report.sh >> /var/log/reports.log 2>&1
# Verify cron was actually installed correctly
crontab -l
Execution
Terminal window
crontab -l | head -10
Output
Terminal window
# Backup jobs
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1
  • Always test scripts manually before scheduling
  • Include comments explaining purpose and frequency
  • Log with timestamps for easier analysis
  • Implement error handling and notifications
  • Review logs regularly for job failures

Error handling and debugging strategies

Robust error handling prevents cascading failures and aids in debugging.

Code
# ROBUST SCRIPT WITH ERROR HANDLING
cat > /usr/local/bin/robust-backup.sh << 'EOF'
#!/bin/bash
set -eEu # Exit on error, undefined vars, pipe errors
shopt -s pipefail
# Configuration
BACKUP_DIR="/backups"
LOG_FILE="/var/log/backup.log"
LOCK_FILE="/tmp/backup.lock"
MAX_RUNTIME=3600 # 1 hour
# Logging function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}
# Error handler
error_exit() {
local line_no=$1
local exit_code=$2
log "ERROR at line $line_no (exit code: $exit_code)"
rm -f "$LOCK_FILE"
echo "Backup failed at line $line_no" | mail -s "Backup ERROR" admin@example.com
exit 1
}
# Cleanup on exit
trap 'error_exit ${LINENO} $?' ERR
# Prevent concurrent runs
if [ -f "$LOCK_FILE" ]; then
log "Previous backup still running (lock file exists)"
exit 1
fi
touch "$LOCK_FILE"
trap 'rm -f "$LOCK_FILE"' EXIT
# Main backup logic
log "Backup started"
tar -czf "$BACKUP_DIR/backup-$(date +%Y%m%d_%H%M%S).tar.gz" /home/user/ || {
log "Backup creation failed"
exit 1
}
# Cleanup old backups
find "$BACKUP_DIR" -name "backup-*.tar.gz" -mtime +7 -delete
log "Backup completed successfully"
EOF
chmod +x /usr/local/bin/robust-backup.sh
# Add to crontab
echo "0 2 * * * timeout 4000 /usr/local/bin/robust-backup.sh" | crontab -
Execution
Terminal window
chmod +x /usr/local/bin/robust-backup.sh
  • Use set -e, -E, -u, -o pipefail for strict error handling
  • Implement trap handlers for cleanup
  • Always remove lock files on exit
  • Log detailed error information
  • Send notifications for critical failures

Debugging Common Issues

Troubleshoot and fix common cron problems

Common cron problems and solutions

Systematic checking helps identify the root cause of cron job failures.

Code
Terminal window
# PROBLEM 1: Job never executes
# Symptoms: Scheduled time passes, nothing happens
# Solutions:
# Check 1: Cron daemon is running
systemctl status cron
# Check 2: Verify crontab is installed
crontab -l
# Check 3: Verify system time (jobs scheduled for past times won't run)
date
timedatectl
# Check 4: Check cron logs (varies by system)
# On Debian/Ubuntu:
grep CRON /var/log/syslog | tail -20
# On CentOS/RHEL:
tail -f /var/log/cron
# Check 5: Verify file permissions (user must have read permission)
ls -la /var/spool/cron/crontabs/username
# Check 6: Verify user has cron access
cat /etc/cron.allow # If exists, user must be listed
cat /etc/cron.deny # If exists, user must NOT be listed
# PROBLEM 2: Job runs but doesn't work (environment issues)
# Symptoms: Manual execution works, cron execution fails
# Solutions:
# Create test script to check environment
cat > test-env.sh << 'TESTEOF'
#!/bin/bash
{
echo "User: $(whoami)"
echo "Home: $HOME"
echo "Path: $PATH"
echo "Shell: $SHELL"
echo "PWD: $PWD"
which python3
python3 --version
} > /tmp/cron-env-test.log 2>&1
TESTEOF
# Schedule it
echo "* * * * * /path/to/test-env.sh" | crontab -
# Wait a minute, then check:
cat /tmp/cron-env-test.log
# Fix: Set environment variables in crontab
crontab -e
# Add at top:
# SHELL=/bin/bash
# PATH=/usr/local/bin:/usr/bin:/bin
# HOME=/home/username
# PROBLEM 3: Permission denied errors
# Symptoms: Cron log shows "Permission denied"
# Solutions:
# Check script permissions
ls -la /path/to/script.sh
# Fix: Make executable
chmod +x /path/to/script.sh
# Check user permissions for target files
ls -la /var/log/backup.log
# Fix: Change permissions or ownership
sudo chown username /var/log/backup.log
# PROBLEM 4: Command not found in cron
# Symptoms: Works manually, "command not found" in cron
# Solutions:
# Use ABSOLUTE PATHS
# BAD:
* * * * * backup.sh
# GOOD:
* * * * * /home/user/backup.sh
# Or use full path with which:
which backup.sh # Returns: /usr/local/bin/backup.sh
* * * * * /usr/local/bin/backup.sh
# PROBLEM 5: Job runs at wrong time
# Symptoms: Job runs at unexpected time
# Solutions:
# Check system time zone
date
timedatectl
# Verify cron schedule with crontab.guru
# Remember: DST changes affect cron times
# If changed timezone, reboot may be needed
sudo reboot
Execution
Terminal window
systemctl status cron && echo "Cron daemon is running"
Output
Terminal window
Active: active (running) since Fri 2025-02-28 10:00:00 UTC
Cron daemon is running
  • Start with basic checks: daemon running, crontab installed
  • Check both syslog and /var/log/cron
  • Test with minimal environment: env -i bash -c 'command'
  • Always use absolute paths
  • Set environment variables in crontab

Monitoring and logging cron jobs

Regular log monitoring helps identify issues early and verify job execution.

Code
Terminal window
# SETUP MONITORING FOR CRON JOBS
# 1. View cron logs (system-wide)
# On Debian/Ubuntu (older):
grep CRON /var/log/syslog | tail -50
# On Debian/Ubuntu (modern with journald):
journalctl -u cron --since "2 hours ago"
# On CentOS/RHEL:
tail -100 /var/log/cron
# 2. Monitor cron log in real-time
journalctl -u cron -f # Follow mode
tail -f /var/log/cron
# 3. Filter cron logs by user
journalctl -u cron | grep username
grep "username" /var/log/cron
# 4. Check for failed jobs in last 24 hours
journalctl -u cron -S "24 hours ago" | grep -i "error\|fail\|exit"
# 5. Count job executions per hour
grep "username" /var/log/cron | cut -d: -f1-3 | sort | uniq -c
# 6. Verify job last execution time
stat /path/to/output/file # Check modification time
ls -la /path/to/output/file
# 7. Create wrapper script with comprehensive logging
cat > /usr/local/bin/logging-wrapper.sh << 'EOF'
#!/bin/bash
SCRIPT="$1"
LOG_DIR="/var/log/cron-jobs"
LOG_FILE="$LOG_DIR/$(basename "$SCRIPT" .sh).log"
mkdir -p "$LOG_DIR"
{
echo "========================================"
echo "Started: $(date '+%Y-%m-%d %H:%M:%S')"
echo "User: $(whoami)"
echo "Command: $SCRIPT"
echo "========================================"
"$SCRIPT"
EXIT_CODE=$?
echo "========================================"
echo "Completed: $(date '+%Y-%m-%d %H:%M:%S')"
echo "Exit code: $EXIT_CODE"
echo "========================================"
[ $EXIT_CODE -ne 0 ] && echo "FAILED: $SCRIPT" || echo "SUCCESS: $SCRIPT"
} >> "$LOG_FILE" 2>&1
exit $EXIT_CODE
EOF
chmod +x /usr/local/bin/logging-wrapper.sh
# Use in crontab:
# 0 2 * * * /usr/local/bin/logging-wrapper.sh /path/to/backup.sh
Execution
Terminal window
journalctl -u cron --since "1 hour ago" | tail -20
Output
Terminal window
Feb 28 14:05:01 hostname CRON[12345]: (username) CMD (/path/to/backup.sh)
Feb 28 14:05:05 hostname CRON[12345]: (username) CMDEND (/path/to/backup.sh)
  • Check both journalctl (systemd) and /var/log/cron
  • Create wrapper scripts for detailed logging
  • Monitor log files for errors and patterns
  • Archive and rotate logs to manage disk space
  • Set up alerts for failed jobs using grep and mail