Crontab Tutorial: Schedule Tasks on Linux (Beginner Guide)

5 min read
Beginner Cron Linux Automation Tutorial

Quick Answer: crontab -e opens your cron jobs. Add a line like 0 2 * /opt/backup.sh to run backup.sh at 2 AM daily. Format: minute hour day-of-month month day-of-week command. Use our Crontab Explainer to translate any expression.

What is Crontab?

Crontab is Linux's built-in task scheduler. It runs commands automatically at specified times — backups at midnight, log cleanup every week, health checks every 5 minutes.

Every user has their own crontab. Root has a separate one for system tasks.

Basic Commands

# Edit your cron jobs
crontab -e

# List your cron jobs
crontab -l

# Remove all your cron jobs (careful!)
crontab -r

# Edit root's crontab
sudo crontab -e

# Edit another user's crontab
sudo crontab -u www-data -e

Cron Syntax

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * * command
Symbol Meaning Example
* Every * = every minute
*/N Every N /5 * = every 5 minutes
N At exactly N 0 2 * = at 2:00 AM
N,M At N and M 0,30 = at :00 and :30
N-M Range N to M 0 9-17 * = every hour 9 AM to 5 PM

Common Examples

Time-Based

# Every minute
* * * * * /opt/scripts/check.sh

# Every 5 minutes
*/5 * * * * /opt/scripts/monitor.sh

# Every 15 minutes
*/15 * * * * /opt/scripts/sync.sh

# Every hour (at minute 0)
0 * * * * /opt/scripts/hourly.sh

# Every day at midnight
0 0 * * * /opt/scripts/daily.sh

# Every day at 2:30 AM
30 2 * * * /opt/scripts/backup.sh

# Every Monday at 9 AM
0 9 * * 1 /opt/scripts/weekly-report.sh

# Every weekday at 9 AM
0 9 * * 1-5 /opt/scripts/workday.sh

# First day of every month at midnight
0 0 1 * * /opt/scripts/monthly.sh

# Every 6 hours
0 */6 * * * /opt/scripts/periodic.sh

# Twice a day (8 AM and 8 PM)
0 8,20 * * * /opt/scripts/twice-daily.sh

Real-World Tasks

# Backup database every night at 2 AM
0 2 * * * mysqldump -u root mydb | gzip > /backups/db-$(date +\%Y\%m\%d).sql.gz

# Clean old log files every Sunday at 3 AM
0 3 * * 0 find /var/log -name "*.log" -mtime +30 -delete

# Renew SSL certificates (twice daily, Let's Encrypt recommends)
0 0,12 * * * certbot renew --quiet

# Check disk space, email alert if >90%
*/30 * * * * df -h / | awk 'NR==2{if($5+0>90) print}' | mail -s "Disk Alert" [email protected]

# Restart a service every night (if it has memory leaks)
0 4 * * * systemctl restart myapp

# Pull latest code and restart (auto-deploy)
*/10 * * * * cd /opt/myapp && git pull && systemctl restart myapp

# Sync files to backup server
0 1 * * * rsync -avz /data/ backup-server:/backups/data/

Logging Cron Output

By default, cron output goes to your system mail. Better options:

# Log output to a file
0 2 * * * /opt/backup.sh >> /var/log/backup.log 2>&1

# Discard output (silent)
0 2 * * * /opt/backup.sh > /dev/null 2>&1

# Log only errors
0 2 * * * /opt/backup.sh >> /var/log/backup.log 2>> /var/log/backup-errors.log

The 2>&1 redirects stderr to the same place as stdout.

Important Rules

Use Full Paths

Cron runs with a minimal environment. Always use full paths:

# Bad (might not find the command)
0 2 * * * backup.sh

# Good
0 2 * * * /opt/scripts/backup.sh

# Or set PATH at the top of crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 2 * * * backup.sh

Escape Percent Signs

In crontab, % has special meaning (newline). Escape it with \%:

# Bad
0 2 * * * echo "Today is $(date +%Y-%m-%d)"

# Good
0 2 * * * echo "Today is $(date +\%Y-\%m-\%d)"

Make Scripts Executable

chmod +x /opt/scripts/backup.sh

Add a Shebang

Your scripts should start with:

#!/bin/bash

System-Wide Cron

Besides user crontabs, Linux has system cron directories:

Location Schedule
/etc/cron.d/ Custom schedules (like crontab format)
/etc/cron.daily/ Runs once per day
/etc/cron.weekly/ Runs once per week
/etc/cron.monthly/ Runs once per month
/etc/cron.hourly/ Runs once per hour

Drop a script into any of these directories and it runs automatically:

# Run daily
sudo cp myscript.sh /etc/cron.daily/
sudo chmod +x /etc/cron.daily/myscript.sh

Troubleshooting

Problem Fix
Cron job not running Check crontab -l — is it there? Check syntax
Runs but nothing happens Add logging: >> /tmp/cron.log 2>&1
Command not found Use full paths: /usr/bin/python3 not python3
Script works manually but not in cron Environment differs — set PATH in crontab
Runs at wrong time Check server timezone: timedatectl
Permission denied chmod +x script.sh and check file ownership
# Check if cron service is running
systemctl status cron

# Check cron logs
grep CRON /var/log/syslog | tail -20

# Check your timezone
timedatectl

Cron vs systemd Timers

Cron systemd Timer
Simplicity Simple one-liner Requires two files
Logging Manual Built into journalctl
Dependencies None Can depend on other services
Missed runs Skipped Can catch up (Persistent=true)
Best for Simple scheduled tasks Complex service scheduling

For most tasks, cron is fine. Use systemd timers for services that need dependency management.

Shorthand Schedules

Shortcut Equivalent When
@reboot -- Once at startup
@yearly 0 0 1 1 * January 1st
@monthly 0 0 1 First of month
@weekly 0 0 0 Every Sunday
@daily 0 0 * Every midnight
@hourly 0 Every hour
@reboot /opt/scripts/startup.sh
@daily /opt/backup.sh >> /var/log/backup.log 2>&1

Related Tools

See Also