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