Crontab Scheduler Guide — Cron Expressions and Practical Examples

What Is cron?

cron is a system daemon in Linux/Unix that schedules and executes recurring tasks. It automatically handles periodic tasks like backups, log cleanup, report generation, and data synchronization without manual intervention.

Here’s a summary of cron-related terminology.

TermDescription
cron daemon (crond)Scheduler process running in the background
crontabConfiguration file defining the list of cron jobs
cron jobAn individual task registered in crontab
cron expression5-field expression specifying execution time

Cron Expression Syntax

A cron expression specifies execution time using 5 fields.

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, both 0 and 7 are Sunday)
│ │ │ │ │
* * * * *  command to execute

Commonly used patterns:

# Run every minute
* * * * * /opt/scripts/healthcheck.sh

# Run at the top of every hour
0 * * * * /opt/scripts/hourly-report.sh

# Run daily at 3:00 AM
0 3 * * * /opt/scripts/daily-backup.sh

# Run every Monday at 9:00 AM
0 9 * * 1 /opt/scripts/weekly-report.sh

# Run at midnight on the 1st of every month
0 0 1 * * /opt/scripts/monthly-cleanup.sh

# Run at 8:00 AM on weekdays (Mon-Fri)
0 8 * * 1-5 /opt/scripts/workday-task.sh

# Run every 10 minutes
*/10 * * * * /opt/scripts/check-service.sh

# Run daily at 9:00 AM and 6:00 PM
0 9,18 * * * /opt/scripts/sync-data.sh

# Run daily at 2:00 AM from January to March
0 2 * 1-3 * /opt/scripts/quarterly-job.sh

Special character meanings:

CharacterMeaningExample
*Every value* * * * * (every minute)
,Multiple values0,30 * * * * (at 0 and 30 minutes)
-Range1-5 (Mon-Fri)
/Interval*/15 (every 15)

crontab Commands

Commands for editing and managing crontab files.

# Edit current user's crontab
crontab -e

# List current user's crontab
crontab -l
# 0 3 * * * /opt/scripts/daily-backup.sh
# */10 * * * * /opt/scripts/healthcheck.sh

# Check specific user's crontab (requires root)
sudo crontab -u deploy -l

# Delete entire crontab (caution!)
crontab -r

# Confirm before deleting
crontab -ri

How to set environment variables in crontab:

# Environment variable settings in crontab (edit via crontab -e)
# cron runs in a minimal environment, so PATH must be specified
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com

# Load environment variables file before execution
0 3 * * * source /opt/my-app/.env && /opt/scripts/backup.sh

# Or use absolute paths explicitly
0 3 * * * /usr/bin/env bash -c 'source /opt/my-app/.env && /opt/scripts/backup.sh'

Setting MAILTO sends the cron job’s output (stdout/stderr) via email. If email is unnecessary, redirect the output.

Checking Logs

How to verify whether cron jobs ran and check for errors.

# cron daemon log (Ubuntu/Debian)
sudo grep CRON /var/log/syslog
# Mar  5 03:00:01 server CRON[1234]: (deploy) CMD (/opt/scripts/daily-backup.sh)

# cron daemon log (CentOS/RHEL)
sudo grep CRON /var/log/cron

# Check only recent cron execution records
sudo grep CRON /var/log/syslog | tail -20

# Check cron execution records for a specific user
sudo grep "CRON.*deploy" /var/log/syslog

Patterns for saving cron job output to log files.

# Record both stdout and stderr to a log file
0 3 * * * /opt/scripts/backup.sh >> /var/log/my-backup.log 2>&1

# Create date-based log files
0 3 * * * /opt/scripts/backup.sh >> /var/log/backup-$(date +\%Y\%m\%d).log 2>&1

# Completely suppress output (not recommended — cannot trace errors)
0 3 * * * /opt/scripts/backup.sh > /dev/null 2>&1

In crontab, % is interpreted as a newline. You must escape it as \% when using % within commands.

Practical Automation Examples

Database Backup Script

#!/bin/bash
# /opt/scripts/backup-db.sh
# PostgreSQL daily backup script

# Environment variables
BACKUP_DIR="/opt/backups/db"
DB_NAME="myapp_production"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7

# Create backup directory
mkdir -p "${BACKUP_DIR}"

# Backup with pg_dump (gzip compressed)
pg_dump "${DB_NAME}" | gzip > "${BACKUP_DIR}/${DB_NAME}_${DATE}.sql.gz"

# Check if backup succeeded
if [ $? -eq 0 ]; then
    echo "[$(date)] Backup successful: ${DB_NAME}_${DATE}.sql.gz"
    # Delete old backups (older than 7 days)
    find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete
    echo "[$(date)] Cleaned up backups older than ${RETENTION_DAYS} days"
else
    echo "[$(date)] Backup failed: ${DB_NAME}" >&2
    exit 1
fi

Log Cleanup Script

#!/bin/bash
# /opt/scripts/cleanup-logs.sh
# Script to clean up old log files

LOG_DIRS=(
    "/var/log/my-app"
    "/var/log/nginx"
    "/opt/my-app/logs"
)

RETENTION_DAYS=30

for dir in "${LOG_DIRS[@]}"; do
    if [ -d "${dir}" ]; then
        # Delete log files older than specified days
        deleted=$(find "${dir}" -name "*.log" -mtime +${RETENTION_DAYS} -delete -print | wc -l)
        # Also delete compressed logs
        deleted_gz=$(find "${dir}" -name "*.log.gz" -mtime +${RETENTION_DAYS} -delete -print | wc -l)
        echo "[$(date)] ${dir}: ${deleted} logs, ${deleted_gz} compressed logs deleted"
    fi
done

# Report disk usage
echo "[$(date)] Disk usage:"
df -h / | tail -1

crontab Registration

# Register via crontab -e
# Daily DB backup at 3:00 AM
0 3 * * * /opt/scripts/backup-db.sh >> /var/log/backup-db.log 2>&1
# Weekly log cleanup at 4:00 AM on Sundays
0 4 * * 0 /opt/scripts/cleanup-logs.sh >> /var/log/cleanup.log 2>&1
# Service health check every 5 minutes
*/5 * * * * curl -sf http://localhost:3000/health > /dev/null || systemctl restart my-app

Debugging cron Jobs

Things to check when cron jobs don’t work as expected.

# 1. Verify the script has execute permission
ls -l /opt/scripts/backup-db.sh
chmod +x /opt/scripts/backup-db.sh

# 2. Run the script manually to check for errors
/opt/scripts/backup-db.sh

# 3. Test in cron environment (simulate minimal environment)
env -i SHELL=/bin/bash PATH=/usr/bin:/bin HOME=/home/deploy /opt/scripts/backup-db.sh

# 4. Verify the cron daemon is running
systemctl status cron
# ● cron.service - Regular background program processing daemon
#      Active: active (running)

# 5. Validate cron expression (use crontab.guru)
# https://crontab.guru/#0_3_*_*_*

Practical Tips

  • Use absolute paths: cron does not load .bashrc/.profile, so PATH is limited. Use absolute paths (/usr/bin/python3) for all commands in scripts, or declare PATH at the top of the script.
  • Always redirect output: If you don’t redirect cron job output to a log file (>> /var/log/xxx.log 2>&1), output accumulates as emails or is lost entirely.
  • Shorthand expressions: Shortcuts like @reboot (on boot), @daily (midnight daily), @hourly (top of every hour), @weekly (Sunday midnight), and @monthly (1st at midnight) are also supported.
  • Prevent concurrent execution: For long-running tasks, use flock to prevent duplicate runs. Example: 0 * * * * flock -n /tmp/mylock.lock /opt/scripts/long-task.sh.
  • Compare with systemd timers: For new projects, consider systemd timers as well. They offer better log management than cron and support Persistent=true to catch up on missed runs. However, for simple recurring tasks, cron is easier to configure.

Was this article helpful?