Cron Syntax in 60 Seconds
A cron expression has 5 fields:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * * command
Common patterns:
* * * * * # Every minute
*/5 * * * * # Every 5 minutes
0 * * * * # Every hour (at minute 0)
0 0 * * * # Every day at midnight
0 0 * * 0 # Every Sunday at midnight
0 0 1 * * # First day of every month
30 2 * * 1-5 # Weekdays at 2:30 AM
Edit your crontab:
crontab -e # Edit current user's crontab
sudo crontab -e # Edit root's crontab
crontab -l # List current cron jobs
Real-World Example: Database Backup
Automatically back up your PostgreSQL database every night:
# Create backup script
sudo nano /usr/local/bin/db-backup.sh
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR=/home/deploy/backups
DB_NAME=myapp
mkdir -p $BACKUP_DIR
# Dump database
pg_dump $DB_NAME | gzip > $BACKUP_DIR/db_${DATE}.sql.gz
# Delete backups older than 7 days
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +7 -delete
echo "Backup completed: db_${DATE}.sql.gz"
chmod +x /usr/local/bin/db-backup.sh
Schedule it:
crontab -e
# Add this line:
0 3 * * * /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1
This runs at 3 AM daily, compresses the backup, keeps only the last 7 days, and logs the output.
Real-World Example: Cleanup Temp Files
Clean up temporary files that file conversion tools create:
# Every hour, delete temp files older than 1 hour
0 * * * * find /tmp/reformat -type f -mmin +60 -delete 2>/dev/null
# Every day at 4am, delete old log files
0 4 * * * find /var/log/myapp -name "*.log" -mtime +30 -delete
# Every 15 minutes, check disk space and alert
*/15 * * * * /usr/local/bin/disk-check.sh
Real-World Example: Health Check and Auto-Restart
Monitor your application and restart it if it goes down:
sudo nano /usr/local/bin/health-check.sh
#!/bin/bash
SERVICE="myapi"
URL="http://127.0.0.1:8000/health"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 $URL)
if [ "$HTTP_CODE" != "200" ]; then
echo "$(date): $SERVICE is down (HTTP $HTTP_CODE). Restarting..." >> /var/log/health-check.log
systemctl restart $SERVICE
fi
chmod +x /usr/local/bin/health-check.sh
crontab -e
# Check every 2 minutes
*/2 * * * * /usr/local/bin/health-check.sh
This is a simple but effective uptime monitor. For production systems, pair this with an external monitoring service like UptimeRobot or Betterstack.
Debugging Cron Jobs
Cron jobs fail silently by default. Here's how to debug:
1. Always redirect output to a log file:* * * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
2. Check cron daemon logs:
grep CRON /var/log/syslog | tail -20
3. Common problems:
- PATH is different — cron runs with minimal PATH. Use full paths:
# Bad
python script.py
# Good
/usr/bin/python3 /home/deploy/script.py
- Environment variables missing — cron doesn't load your
.bashrc. Source them:
* * * * * source /home/deploy/.env && /path/to/script.sh
- Permission denied — make sure the script is executable:
chmod +x /path/to/script.sh
4. Test by running the exact cron command manually:
/bin/bash -c '/path/to/your/cron/command'