12.1. Cron & At#
12.1.1. Common Pitfalls#
1. Using relative paths in cron
# BAD: script might not be in cron's PATH
0 2 * * * backup.sh
# GOOD: use absolute paths
0 2 * * * /usr/local/bin/backup.sh
2. Forgetting to redirect output
# BAD: output causes email to be sent (if sendmail installed)
0 * * * * /script.sh
# GOOD: redirect to file
0 * * * * /script.sh >> /var/log/script.log 2>&1
3. Assuming cron has same environment as login shell
# BAD: Uses user's PATH and environment
crontab -e
# 0 * * * * mycommand
# GOOD: Set environment explicitly
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
0 * * * * /usr/local/bin/mycommand
4. Not using full paths in scripts
#!/bin/bash
# BAD: grep, sed, etc. might not be in PATH
command | grep pattern | sed 's/old/new/'
# GOOD: Use full paths
/bin/ls | /bin/grep pattern | /bin/sed 's/old/new/'
5. Scheduling conflicts
# BAD: Multiple heavy jobs at same time
0 2 * * * /backup.sh # Backup at 2 AM
0 2 * * * /report.sh # Report at 2 AM (same time!)
0 2 * * * /maintenance.sh # Maintenance at 2 AM
# GOOD: Stagger the times
0 2 * * * /backup.sh
30 2 * * * /report.sh
0 3 * * * /maintenance.sh
12.1.2. Real-World Example: Complete Cron Setup#
#!/bin/bash
# INSTALL CRON JOBS FOR SYSTEM MAINTENANCE
# Create script directory
SCRIPT_DIR="/usr/local/bin/maintenance"
mkdir -p "$SCRIPT_DIR"
# Daily backup script
cat > "$SCRIPT_DIR/daily_backup.sh" << 'EOF'
#!/bin/bash
set -euo pipefail
BACKUP_DIR="/backups"
RETENTION_DAYS=30
# Create backup
backup_file="$BACKUP_DIR/daily_$(date +%Y%m%d).tar.gz"
mkdir -p "$BACKUP_DIR"
tar -czf "$backup_file" /etc /home 2>/var/log/backup_error.log
# Cleanup old backups
find "$BACKUP_DIR" -name "daily_*.tar.gz" -mtime +$RETENTION_DAYS -delete
# Log success
echo "[$(date)] Backup completed: $backup_file" >> /var/log/backups.log
EOF
chmod +x "$SCRIPT_DIR/daily_backup.sh"
# Weekly report script
cat > "$SCRIPT_DIR/weekly_report.sh" << 'EOF'
#!/bin/bash
# Generate weekly system report and email admin
REPORT_FILE="/tmp/weekly_report.txt"
{
echo "Weekly System Report"
echo "Generated: $(date)"
echo ""
echo "=== Disk Usage ==="
df -h
echo ""
echo "=== Memory ==="
free -h
echo ""
echo "=== Top Processes ==="
ps aux --sort=-%mem | head -6
} > "$REPORT_FILE"
mail -s "Weekly Report" admin@example.com < "$REPORT_FILE"
EOF
chmod +x "$SCRIPT_DIR/weekly_report.sh"
# Install crontab entries
{
echo "# System Maintenance Schedule"
echo "SHELL=/bin/bash"
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
echo ""
echo "# Daily backup at 2:00 AM"
echo "0 2 * * * $SCRIPT_DIR/daily_backup.sh >> /var/log/cron.log 2>&1"
echo ""
echo "# Weekly report every Monday at 9:00 AM"
echo "0 9 * * 1 $SCRIPT_DIR/weekly_report.sh >> /var/log/cron.log 2>&1"
echo ""
echo "# System checks every hour"
echo "0 * * * * /usr/local/bin/system_check.sh >> /var/log/cron.log 2>&1"
} | crontab -
echo "Cron jobs installed successfully"
12.1.3. The at Command for One-Time Jobs#
The at command schedules a one-time job for a specific time.
12.1.3.1. Basic at Usage#
# Schedule a job for a specific time
at 2pm tomorrow
> /usr/local/bin/backup.sh
> Ctrl+D
# Schedule for specific date/time
at 10:30 AM December 25
> echo "Merry Christmas!" | mail admin@example.com
> Ctrl+D
# View scheduled jobs
atq
# Remove a job
atrm job_id
# View job details
at -c job_id
# Schedule from stdin
echo "backup.sh" | at 3am
12.1.3.2. at Time Specifications#
# Absolute times
at 10:30 AM
at 2:30 PM
at 23:00
at midnight
at noon
# Relative times
at now + 5 minutes
at now + 2 hours
at now + 3 days
at now + 1 week
# Specific dates
at 10am tomorrow
at 10am January 15
at 10am 2025-12-25
# Day names
at 2pm Monday
at 10am Friday next week
12.1.4. Cron Environment and Best Practices#
12.1.4.1. Cron Environment Limitations#
# Cron runs with minimal environment
# No terminal: can't use interactive commands
# Limited PATH: must use full paths
# No user shell: different from login shell
# Different HOME directory
# BAD: Relies on PATH and interactive behavior
0 * * * * backup_data.sh
# GOOD: Use full paths and explicit settings
0 * * * * /usr/local/bin/backup_data.sh
# BETTER: Set environment in crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
SHELL=/bin/bash
0 * * * * /usr/local/bin/backup_data.sh
12.1.4.2. Cron Logging#
# Cron output is mailed to user (if sendmail installed)
# To log to file, redirect in crontab:
# Log stdout and stderr to file
0 * * * * /usr/local/bin/task.sh >> /var/log/task.log 2>&1
# Log to syslog
0 * * * * /usr/local/bin/task.sh 2>&1 | logger -t cron_task
# Suppress output
0 * * * * /usr/local/bin/task.sh > /dev/null 2>&1
12.1.4.3. Crontab Directory#
# System-wide cron files (run as root)
/etc/cron.d/
/etc/cron.daily/
/etc/cron.hourly/
/etc/cron.monthly/
/etc/cron.weekly/
# User crontabs
/var/spool/cron/crontabs/
# Example system cron file
/etc/cron.d/example
#min hour day month dow user command
0 2 * * * root /usr/local/bin/maintenance.sh
12.1.5. Cron: Recurring Task Scheduler#
Cron executes tasks at specified intervals. Cron jobs are stored in crontab files.
12.1.5.1. Viewing and Editing Crontab#
# View current user's crontab
crontab -l
# Edit current user's crontab (opens in editor)
crontab -e
# View another user's crontab (as root)
sudo crontab -u username -l
# Install crontab from file
crontab -i file.txt
# Remove all cron jobs for current user
crontab -r
12.1.5.2. Crontab Syntax#
minute (0-59) hour (0-23) day (1-31) month (1-12) weekday (0-6) command
12.1.5.3. Common Crontab Entries#
# Every hour
0 * * * * /usr/local/bin/hourly_task.sh
# Every day at 2:30 AM
30 2 * * * /usr/local/bin/daily_backup.sh
# Every Monday at 9:00 AM
0 9 * * 1 /usr/local/bin/weekly_report.sh
# Every 15 minutes
*/15 * * * * /usr/local/bin/check_status.sh
# First day of month at midnight
0 0 1 * * /usr/local/bin/monthly_maintenance.sh
# Weekdays (Monday-Friday) at 5:00 PM
0 17 * * 1-5 /usr/local/bin/weekday_task.sh
# Every 4 hours
0 */4 * * * /usr/local/bin/periodic_sync.sh
# At reboot
@reboot /usr/local/bin/startup_script.sh