What Is a Cron Job in Linux? Complete Guide to Scheduled Tasks

2024/01/31

In Linux, a cron job is the core tool for automating scheduled tasks. Once configured, the system automatically executes backups, log cleanup, service monitoring, and other repetitive tasks at specified times โ€” greatly improving operational efficiency. This guide covers everything from cron fundamentals, time format syntax, and practical examples to debugging tips.

What Is a Cron Job?

Cron is a built-in scheduling utility in Unix-like systems (including Linux). Its name derives from the Greek word “chronos” (time). The cron daemon runs continuously in the background, checking the schedule configuration once every minute and automatically executing the corresponding commands or scripts when the time conditions are met.

Common use cases for cron jobs:

  • Automated backups: Back up databases or important files every night at 3 AM
  • Log cleanup: Periodically delete logs older than 30 days to prevent disk space exhaustion
  • System monitoring: Check whether services are running normally every few minutes
  • Report generation: Automatically generate analytics reports weekly and send them via email
  • Certificate renewal: Automatically renew SSL certificates (e.g., Let’s Encrypt’s certbot)

Cron Job vs systemd Timer

Modern Linux systems (especially Ubuntu 20.04+) also offer systemd timers as an alternative to cron. Each approach has its own strengths and weaknesses:

ComparisonCron Jobsystemd Timer
Configuration difficultySimple, single-line setupMore complex, requires two config files
LoggingMust manually redirect to log filesAutomatically integrated with journald
Missed execution handlingMissed runs are simply skippedCan be configured to run after boot (OnBootSec)
Dependency managementNot supportedSupports systemd service dependencies
Best suited forQuick, simple scheduled tasksComplex service management scheduling

For most everyday scheduling needs, cron job syntax is simple and effective, making it the most commonly used choice.


Crontab Time Format

The cron job time format consists of five fields followed by a command:

* * * * * command to execute
โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ Day of Week (0-7, both 0 and 7 represent Sunday)
โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€ Month (1-12)
โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€ Day of Month (1-31)
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Hour (0-23)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Minute (0-59)

Field Reference

FieldDescriptionAllowed Values
MINMinute0 to 59
HOURHour0 to 23
DOMDay of Month1 to 31
MONMonth1 to 12, or English abbreviations (Jan, Feb, Mar…)
DOWDay of Week0 (Sunday) to 6 (Saturday), 7 also means Sunday, or English abbreviations (Sun, Mon…)
CMDCommand to executeAny executable program or script (with arguments)

Special Characters

In addition to numeric values, cron supports the following special characters for more flexible scheduling:

CharacterNameDescriptionExample
*AsteriskEvery possible value* in the minute field = every minute
,CommaList multiple values1,15,30 = at minute 1, 15, and 30
-HyphenSpecify a range9-17 = from 9 AM to 5 PM
/SlashSpecify step intervals*/5 = every 5 units

Crontab Cheat Sheet

Schedule DescriptionCrontab Expression
Every minute* * * * *
Every 5 minutes*/5 * * * *
Every 15 minutes*/15 * * * *
Every hour on the hour0 * * * *
Every day at 2:00 AM0 2 * * *
Every day at 8:30 AM30 8 * * *
Every Monday at 9:00 AM0 9 * * 1
Every Monday, Wednesday, and Friday at 1:00 AM0 1 * * 1,3,5
1st of every month at midnight0 0 1 * *
Last day of month (approximate) at midnight0 0 28-31 * *
January 1st at midnight (yearly)0 0 1 1 *
Weekdays (Monโ€“Fri) at 8:00 AM0 8 * * 1-5

Crontab Commands

Basic Commands

# Edit the current user's crontab (opens the default editor)
crontab -e

# List all scheduled jobs for the current user
crontab -l

# Remove all scheduled jobs for the current user (dangerous! back up first)
crontab -r

# Back up the current crontab to a file
crontab -l > ~/crontab_backup.txt

# Restore crontab from a backup file
crontab ~/crontab_backup.txt

Managing Other Users’ Crontabs

# Edit a specific user's crontab as root
sudo crontab -u username -e

# View a specific user's scheduled jobs
sudo crontab -u username -l

# Remove a specific user's scheduled jobs
sudo crontab -u username -r

Crontab Guru โ€” Visual Cron Expression Editor

Crontab Guru
  • A handy tool that lets you quickly edit and preview the meaning of cron time expressions in real time โ€” perfect for beginners unfamiliar with the syntax

Practical Scheduling Examples

Basic Examples

# Run a backup script every day at 3:00 AM
0 3 * * * /home/benz/scripts/backup.sh

# Delete logs older than 30 days every Monday at 2:00 AM
0 2 * * 1 find /var/log/app -name "*.log" -mtime +30 -delete

# Log disk usage every hour
0 * * * * df -h >> /var/log/disk_usage.log

# Check if nginx is running every 5 minutes; restart if it's not
*/5 * * * * systemctl is-active nginx || systemctl restart nginx

# Send a daily system status report email at 8:00 AM
0 8 * * * /home/benz/scripts/daily_report.sh | mail -s "Daily Report" admin@example.com

Advanced Examples (Logging and Error Handling)

By default, cron discards command output (or sends it via email through MAILTO). It is recommended to redirect both stdout and stderr to a log file for easier troubleshooting:

# Redirect both stdout and stderr to a log file
0 3 * * * /home/benz/scripts/backup.sh >> /var/log/cron_backup.log 2>&1

# 2>&1 means: redirect stderr (2) to wherever stdout (1) points
# >> appends to the file without overwriting existing content

# Log only errors
0 3 * * * /home/benz/scripts/backup.sh > /dev/null 2>> /var/log/cron_errors.log

# Add timestamps to log entries
0 * * * * echo "$(date '+%Y-%m-%d %H:%M:%S') - Execution completed" >> /var/log/hourly.log

Setting Environment Variables in Cron

# Set environment variables at the top of the crontab (applies to all jobs)
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=admin@example.com

# With MAILTO set, cron will automatically send an email whenever a job produces output
# Set it to an empty string to disable email notifications:
MAILTO=""

0 3 * * * /home/benz/scripts/backup.sh

Cron Job Environment Variables

This is the most common “gotcha” with cron jobs โ€” a command that runs perfectly in your terminal fails when placed in cron. The cause is almost always different environment variables.

Why Are Cron’s Environment Variables Different from the Terminal?

When you log into a terminal, the system loads configuration files like .bashrc and .bash_profile, which set up environment variables such as PATH, JAVA_HOME, and others. However, cron runs in a non-interactive, minimal environment that does not load these configuration files, resulting in a very short PATH:

# PATH in your terminal (long, includes many custom paths)
echo $PATH
# /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/benz/.local/bin

# Default PATH in cron (very short)
# /usr/bin:/bin

Solutions

Method 1: Set PATH at the top of your crontab (Recommended)

# Add these lines at the top of crontab -e
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash

# All subsequent jobs will use this PATH
0 3 * * * backup.sh

Method 2: Use absolute paths in your commands

# Don't write
0 3 * * * node /home/benz/app/index.js

# Use the full path instead
0 3 * * * /usr/local/bin/node /home/benz/app/index.js

Method 3: Source environment configuration in your script

#!/bin/bash
# Load bash environment configuration at the start of the script
source /home/benz/.bashrc
# or
source /etc/profile

# Then run the actual logic
/usr/local/bin/node /home/benz/app/index.js

Cron Job Debugging Tips

When a scheduled job does not execute as expected, the following methods can help identify the problem:

1. Check Cron Logs in the System Journal

# View cron logs on Ubuntu/Debian systems
grep CRON /var/log/syslog | tail -50

# Or use journalctl (systemd-based systems)
journalctl -u cron --since "1 hour ago"

# Monitor cron logs in real time
tail -f /var/log/syslog | grep CRON

2. Verify the Cron Daemon Is Running

# Check the cron service status
systemctl status cron

# If it's not running, start it
sudo systemctl start cron
sudo systemctl enable cron  # Enable auto-start on boot

3. Test Commands in the Same Environment

# Simulate cron's execution environment for testing
env -i PATH=/usr/bin:/bin HOME=/home/benz SHELL=/bin/bash /home/benz/scripts/backup.sh

# Verify the script has execute permissions
ls -l /home/benz/scripts/backup.sh
chmod +x /home/benz/scripts/backup.sh

4. Common Issues Checklist

ProblemLikely CauseSolution
Cron does not run at allcron service is not startedsystemctl start cron
Command not foundPATH does not include the command’s directorySet PATH at the top of crontab or use absolute paths
Script has no execute permissionFile is missing the x permissionchmod +x script.sh
File or directory not foundRelative paths are usedUse absolute paths (e.g., /home/benz/data/)
Runs but has no effectMissing environment variablesAdd source ~/.bashrc in the script

System-Level Cron Configuration

In addition to user-level crontab, Linux provides several system-level scheduling locations:

/etc/crontab โ€” System-Wide Schedule

The /etc/crontab format includes an additional user field compared to user crontabs:

# /etc/crontab format (includes a username field)
# m h  dom mon dow   user    command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )

/etc/cron.d/ โ€” Package-Specific Schedules

Packages often place their own schedule configurations in /etc/cron.d/, using the same format as /etc/crontab:

# List all system-level scheduled jobs
ls /etc/cron.d/

# Common entries include certbot (SSL certificate renewal)
cat /etc/cron.d/certbot

/etc/cron.daily/, cron.weekly/, cron.monthly/

These three directories contain scripts that the system automatically runs daily, weekly, or monthly:

ls /etc/cron.daily/
ls /etc/cron.weekly/
ls /etc/cron.monthly/

# Manually trigger a test run (simulate daily schedule execution)
run-parts /etc/cron.daily

anacron โ€” For Computers That Are Not Always On

If a computer is not running 24/7 (such as a laptop), cron may miss scheduled jobs while the machine is off. anacron compensates by running missed jobs after the system boots:

# View anacron configuration
cat /etc/anacrontab

# Format explanation:
# 1      5   cron.daily   run-parts --report /etc/cron.daily
# period  delay  job-id     command

Frequently Asked Questions (FAQ)

Q1: Should I use cron job or systemd timer?

For most simple scheduling needs, cron job syntax is intuitive and quick to set up โ€” making it the go-to choice. Consider systemd timers only if you need:

  • Precise logging (integrated with journald)
  • Task dependencies (a job must run only after a specific service starts)
  • Missed job recovery after boot (similar to anacron functionality)

Q2: Why does my cron job run fine in the terminal but fail when scheduled?

The three most common causes:

  1. PATH issue: Cron’s PATH is very short and cannot find your command. Solution: add PATH=... at the top of your crontab or use full paths in commands.
  2. Permission issue: The script does not have execute permission (chmod +x script.sh), or it accesses resources that require sudo.
  3. Relative path issue: The script uses relative paths, but cron’s working directory may not be what you expect. Use absolute paths instead.

Q3: Cron can only go down to one-minute intervals. Can I run something every second?

Cron’s minimum resolution is one minute โ€” it cannot execute jobs every second. If you need per-second execution, consider these alternatives:

  • Loop within a script: Write while true; do command; sleep 1; done in a script, then use cron to launch it
  • systemd timer: Use OnCalendar=*:*:0/5 to achieve execution every 5 seconds
  • Background daemon service: For long-term needs, consider writing a systemd service that runs continuously

Further reading: