---
title: "Cron"
description: "Cron is a time-based job scheduler in Unix/Linux that allows you to run scripts or commands periodically. Essential crontab syntax, scheduling patterns, and management commands."
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/cheatsheets/cron
---

# Cron

## Quick Reference

### Field Layout

```
Min  Hour Day  Month Weekday  Command
 *    *    *    *     *       /path/to/command

 ┬    ┬    ┬    ┬     ┬
 │    │    │    │     └─────  Weekday (0=Sunday, 6=Saturday)
 │    │    │    └──────────  Month (1-12)
 │    │    └───────────────  Day (1-31)
 │    └────────────────────  Hour (0-23)
 └─────────────────────────  Minute (0-59)
```

### Operators

| Operator | Name  | Example        | Description      |
| -------- | ----- | -------------- | ---------------- |
| `*`      | Any   | `* * * * *`    | Every minute     |
| `,`      | List  | `0,30 * * * *` | Minutes 0 and 30 |
| `-`      | Range | `9-17 * * * *` | 9 AM to 5 PM     |
| `/`      | Step  | `*/15 * * * *` | Every 15 minutes |

### Special Strings

| String     | Frequency      | Equivalent  |
| ---------- | -------------- | ----------- |
| `@reboot`  | Run at startup | N/A         |
| `@hourly`  | Every hour     | `0 * * * *` |
| `@daily`   | Every day      | `0 0 * * *` |
| `@weekly`  | Every week     | `0 0 * * 0` |
| `@monthly` | Every month    | `0 0 1 * *` |
| `@yearly`  | Every year     | `0 0 1 1 *` |

### Common Patterns

| Pattern        | Meaning                  |
| -------------- | ------------------------ |
| `0 * * * *`    | Every hour               |
| `*/15 * * * *` | Every 15 minutes         |
| `0 0 * * *`    | Daily at midnight        |
| `0 9 * * 1-5`  | 9 AM on weekdays         |
| `0 0 * * 0`    | Sunday at midnight       |
| `0 0 1 * *`    | 1st of month at midnight |

### Essential Commands

```bash
crontab -e              # Edit current user's crontab
crontab -l              # List crontab jobs
crontab -r              # Delete current user's crontab
crontab -u username -e  # Edit user's crontab (root)
crontab -u username -l  # List user's crontab (root)

# System-wide scheduling
ls /etc/cron.{hourly,daily,weekly,monthly}/
cat /etc/crontab
```

---

## Crontab Management

### Install from file

```bash
crontab /path/to/crontab.txt      # Replace entire crontab
crontab -l > backup.txt           # Backup before changes
```

### System logs

```bash
# Debian/Ubuntu
journalctl -u cron -f             # Follow cron logs
grep CRON /var/log/syslog         # Historical logs

# CentOS/RHEL
tail -f /var/log/cron             # Follow cron logs
```

---

## Environment Setup

Always add at top of crontab file:

```bash
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/username
LOGNAME=username
MAILTO=admin@example.com
```

---

## Resources

- [Official Crontab Manual](https://man7.org/linux/man-pages/man5/crontab.5.html)
- [Crontab Guru](https://crontab.guru/) - Visual cron expression explainer
- [Linux Cron Documentation](https://linux.die.net/man/5/crontab)

## Getting Started

Learn what cron is and understand the basics of job scheduling

### What is Cron

Understand cron and its capabilities for job scheduling

**Keywords:** introduction, what, about, cron, scheduler, background

#### Install and verify cron daemon

```bash
# On Debian/Ubuntu
sudo apt-get install cron

# On CentOS/RHEL
sudo yum install cronie

# Start cron daemon
sudo systemctl start cron

# Enable cron to start on boot
sudo systemctl enable cron

# Verify cron is running
sudo systemctl status cron
```

_exec_
```bash
systemctl status cron | grep Active
```

_output_
```bash
Active: active (running) since Fri 2025-02-28 10:00:00 UTC; 2 days ago
```

Install and verify cron daemon is running on the system to enable job scheduling.

- Cron is usually pre-installed on Linux systems
- The daemon must be running for scheduled jobs to execute
- Use systemctl on modern systems (systemd)
- On older systems, use service cron start

#### Basic cron concepts and use cases

```bash
# Cron runs in the background as a daemon
# Jobs are stored in crontab (cron table)
# Each user can have their own crontab file
# System-wide cron jobs are stored in /etc/cron.d/
# Cron uses local system time

# Create a simple backup script
cat > backup.sh << 'EOF'
#!/bin/bash
tar -czf /backups/backup-$(date +%Y%m%d).tar.gz /home/user/documents/
EOF

chmod +x backup.sh

# Schedule it to run daily at 2 AM
echo "0 2 * * * /home/user/backup.sh" | crontab -
```

_exec_
```bash
crontab -l | head -1
```

_output_
```bash
0 2 * * * /home/user/backup.sh
```

Cron executes scheduled scripts and commands automatically according to specified schedules.

- Each user has separate crontab access and permissions
- Root user can schedule system-wide critical tasks
- Cron jobs inherit the user's environment settings
- Jobs run in background without user interaction

#### Cron vs other scheduling methods

```bash
# Cron - recurring scheduled jobs (system daemon)
# Good for: regular backups, log rotation, cleanup tasks
echo "0 0 * * * /scripts/daily-cleanup.sh" | crontab -

# At - run job once at specific time (requires atd daemon)
# Good for: one-time future tasks
echo "backup.sh" | at 2:00 AM tomorrow

# Systemd timers - modern alternative to cron
# Good for: system services with dependencies
# Uses .timer and .service files

# Background processes - shell jobs
# Good for: background execution in current session only
./long-running-script.sh &
```

_exec_
```bash
which cron
```

_output_
```bash
/usr/sbin/cron
```

Cron is the standard daemon for recurring tasks, complemented by other tools for specific use cases.

- Cron persists across reboots
- At command requires atd daemon
- Systemd timers are modern systemd-based alternative
- Background processes (&) only run while shell session active

**Best practices:**

- Always use absolute paths in cron jobs
- Redirect output to log files for debugging
- Test scripts manually before adding to crontab
- Use environment variables wisely
- Document all scheduled jobs

**Common errors:**

- **Job not executing at scheduled time**: Check cron daemon is running, verify crontab syntax, check system time
- **Command not found in cron job**: Use absolute paths (/usr/bin/command, not bare command names)

### Crontab Basics

Understand crontab structure and how to work with it

**Keywords:** crontab, basics, files, structure, user

#### View and understand crontab file structure

```bash
# View current user's crontab
crontab -l

# View another user's crontab (requires root)
sudo crontab -l -u username

# View system-wide crontab
cat /etc/crontab

# View all cron directories
ls -la /etc/cron.* 2>/dev/null

# Check user crontab files location
ls -la /var/spool/cron/crontabs/
```

_exec_
```bash
crontab -l 2>/dev/null || echo "No crontab for current user"
```

_output_
```bash
# /var/spool/cron/crontabs/username
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:47 vixie Exp $)
0 2 * * * /home/user/backup.sh
```

Crontab displays and manages the cron schedule for the current user.

- Each user has their own crontab file in /var/spool/cron/crontabs/
- System crontabs are in /etc/cron.d/ and /etc/crontab
- Always use crontab command to edit, not text editor directly
- crontab -l shows current schedule

#### Account-specific cron directories

```bash
# View daily scheduled jobs (run at 6:25 AM)
ls -la /etc/cron.daily/

# View hourly scheduled jobs (run at 17 minutes past each hour)
ls -la /etc/cron.hourly/

# View weekly scheduled jobs
ls -la /etc/cron.weekly/

# View monthly scheduled jobs
ls -la /etc/cron.monthly/

# Add custom script to daily execution
sudo cp myscript.sh /etc/cron.daily/
sudo chmod 755 /etc/cron.daily/myscript.sh
```

_exec_
```bash
ls /etc/cron.d/ 2>/dev/null | head -5
```

_output_
```bash
anacron
popularity-contest
run-parts
```

System-wide cron directories allow scheduling tasks for all users without individual crontab management.

- Scripts in cron.daily/ run once daily
- Scripts must be executable (chmod +x)
- No file extensions needed in cron directories
- Perfect for system-wide maintenance tasks

### Core Concepts

Understand time-based scheduling and cron job execution

**Keywords:** concepts, time, scheduling, execution, daemon

#### Understand cron timing and timezone

```bash
# Cron uses system time
# Check system time and timezone
date
timedatectl
cat /etc/timezone

# View system clock
hwclock --show

# Update timezone if needed
sudo timedatectl set-timezone America/New_York

# Important: Change timezone, then update cron times
# Cron doesn't automatically adjust for timezone changes
```

_exec_
```bash
date && timedatectl | grep "Time zone"
```

_output_
```bash
Fri Feb 28 15:30:45 UTC 2025
   Time zone: UTC (UTC, +0000)
```

Cron uses the system's time zone, so verify correct time zone configuration for accurate scheduling.

- Cron respects system time zone
- If system time changes, all future jobs recalculate
- DST changes don't auto-adjust cron times
- Use timedatectl or tzconfig to manage time zone

#### Cron job execution environment

```bash
# Cron job runs with minimal environment
# Create a script to test environment
cat > test-env.sh << 'EOF'
#!/bin/bash
{
  echo "=== Cron Job Environment ==="
  echo "User: $(whoami)"
  echo "Home: $HOME"
  echo "Shell: $SHELL"
  echo "PATH: $PATH"
  echo "PWD: $PWD"
} >> /tmp/cron-env.log
EOF

# Add to crontab
echo "* * * * * /path/to/test-env.sh" | crontab -

# Check log after a minute
cat /tmp/cron-env.log
```

_exec_
```bash
echo "Remember: Cron has minimal environment"
```

_output_
```bash
Remember: Cron has minimal environment
```

Cron jobs run with limited environment, so always use absolute paths and set variables explicitly.

- Cron doesn't load shell profile (.bashrc, .bash_profile)
- Home directory may not be set
- PATH is set to /usr/bin:/bin
- Use absolute paths for all scripts and commands
- Set environment variables at top of crontab if needed

**Best practices:**

- Always test scripts before adding to crontab
- Use absolute paths for all commands
- Redirect output to capture job results
- Document all scheduled tasks
- Review system load before scheduling resource-intensive jobs

**Common errors:**

- **Job runs but doesn't work as expected**: Use absolute paths, set environment variables, redirect output to log file
- **Cron job time seems wrong**: Verify system time zone with timedatectl or date

## Crontab Syntax

Learn the complete crontab syntax and field descriptions

### Field Format and Layout

Understanding the five fields that define cron schedules

**Keywords:** format, fields, syntax, layout, minute, hour, day, month, weekday

#### Crontab field structure diagram

```text
# CRON SYNTAX DIAGRAM
Min  Hour Day  Month Weekday  Command
*    *    *    *     *        /path/to/command

┬    ┬    ┬    ┬     ┬
│    │    │    │     └─  Weekday   (0=Sunday, 1=Monday, ..., 6=Saturday)
│    │    │    └──────  Month     (1=January, 2=February, ..., 12=December)
│    │    └───────────  Day       (1-31, specific day of month)
│    └────────────────  Hour      (0-23, 24-hour format)
└─────────────────────  Minute    (0-59, at this minute)


# FIELD RANGES AND ALLOWED VALUES:
Field      Range        Description
──────────────────────────────────────────
Minute     0-59        Minute of the hour
Hour       0-23        Hour of the day (24-hour format)
Day        1-31        Day of the month
Month      1-12        Month (Jan=1, Dec=12)
Weekday    0-7         Day of week (0 & 7 = Sunday, 6 = Saturday)
```

_exec_
```bash
echo "Crontab format: MIN HOUR DAY MONTH WEEKDAY COMMAND"
```

_output_
```bash
Crontab format: MIN HOUR DAY MONTH WEEKDAY COMMAND
```

The crontab uses five time fields followed by the command to execute, with specific value ranges.

- All fields are space-separated
- Asterisk (*) means "any value"
- Fields can contain numbers, ranges, lists, or special operators
- Whitespace must separate each field and command

#### Common field values reference

```bash
# MINUTE (0-59)
0        - At minute 0 (top of hour)
15       - At minute 15 (quarter past)
*/5      - Every 5 minutes
0,30     - At minutes 0 and 30 (twice per hour)

# HOUR (0-23)
0        - At midnight (12 AM)
12       - At noon (12 PM)
13       - At 1 PM
*/4      - Every 4 hours
9-17     - Business hours (9 AM to 5 PM)

# DAY (1-31)
1        - First day of month
15       - Fifteenth day of month
*/2      - Every 2 days
1-7      - First week of month

# MONTH (1-12)
1        - January
12       - December
*/3      - Every 3 months (Jan, Apr, Jul, Oct)
6-8      - June, July, August (summer)

# WEEKDAY (0-7, where 0 and 7 = Sunday)
0        - Sunday
1        - Monday
5        - Friday
6        - Saturday
1-5      - Monday through Friday (weekdays)
```

_exec_
```bash
crontab -l | grep "^[^#]" | head -1 || echo "No scheduled jobs"
```

_output_
```bash
No scheduled jobs
```

Common field values help you understand and construct cron schedules quickly.

- Remember AM/PM: hours 0-23 (0=midnight, 12=noon, 23=11PM)
- Days and months are 1-based (not 0-based like programming)
- Weekday: 0 and 7 both represent Sunday

### Operators and Syntax

Master cron operators for flexible scheduling patterns

**Keywords:** operators, asterisk, comma, dash, slash, range, list

#### Cron operators reference

```text
# CRON OPERATORS

OPERATOR  |  MEANING           |  EXAMPLE              |  EXPLANATION
──────────┼────────────────────┼──────────────────────┼──────────────────────────
*         |  Any value         |  * * * * *           |  Every minute of every day
,         |  Value separator   |  0,30 * * * *        |  At 0 and 30 minutes (twice hourly)
-         |  Range of values   |  9-17 * * * *        |  Every minute from 9 AM to 5 PM
/         |  Step values       |  */15 * * * *        |  Every 15 minutes
L         |  Last             |  L * * *             |  Last day of month (some systems)
W         |  Weekday           |  15W * * *           |  Nearest weekday to 15th (some systems)
#         |  Nth occurrence    |  * * * * 1#2         |  Second Monday (some systems)


# IMPORTANT NOTES:
- L and W operators are NOT standard POSIX cron
- They may only work in some cron implementations
- Stick to *, , , -, / operators for portability
```

_exec_
```bash
echo "Standard operators: * , - /"
```

_output_
```bash
Standard operators: * , - /
```

Cron operators allow flexible scheduling patterns using standard mathematical and listing syntax.

- Always use standard operators (* , - /) for maximum compatibility
- Values in ranges and lists must be valid for the field
- Spaces not allowed within field values (no spaces around , or -)

#### Practical operator examples

```bash
# ASTERISK (*) - Match any value
0 * * * *           # Every hour at minute 0
* * * * *           # Every minute of every day

# COMMA (,) - List specific values
0 8,12,17 * * *     # At 8 AM, 12 PM (noon), and 5 PM
0 0 1,15 * *        # First and 15th day of month at midnight
0 0 * * 0,6         # Sunday and Saturday at midnight

# DASH (-) - Range of values
0 9-17 * * *        # Every hour from 9 AM to 5 PM
30 9-17 * * 1-5     # 30 minutes past hour, 9 AM-5 PM, Mon-Fri
0 0 1-7 * *         # First week of month at midnight

# SLASH (/) - Step values / intervals
*/30 * * * *        # Every 30 minutes
*/5 9-17 * * *      # Every 5 minutes during business hours
0 */6 * * *         # Every 6 hours starting at midnight
0 0 * * */2         # Every 2 days starting from Sunday

# COMBINATIONS
*/15 9-17 * * 1-5   # Every 15 min, 9-5pm, weekdays
0 8-18 * * 1-5      # Every hour 8-6pm, Mon-Fri
```

_exec_
```bash
echo "0 9-17 * * 1-5 /path/to/script.sh" | crontab -
```

Combinations of operators create complex but precise scheduling patterns for real-world needs.

- Steps (/) count from the field's minimum value
- */5 in minutes = every 5 minutes (0, 5, 10, 15, ...)
- 5-55/5 in minutes = 5, 10, 15, 20, ..., 55

### Syntax Validation and Examples

Validate your crontab syntax and learn from examples

**Keywords:** validation, syntax, examples, testing, check

#### Validate crontab syntax before installing

```bash
# Method 1: Use crontab with -i flag to test
crontab -e   # Opens editor, validates on save

# Method 2: Write to temp file, then test
cat > new_cron.txt << 'EOF'
0 2 * * * /usr/local/bin/backup.sh
0 0 * * 0 /usr/local/bin/weekly-report.sh
EOF

# Method 3: Online cron expression tester
# Visit: https://crontab.guru/
# Paste expression and see explanation

# Method 4: Manual validation checklist
# - Check all 5 fields present (space-separated)
# - Minute: 0-59, Hour: 0-23, Day: 1-31
# - Month: 1-12, Weekday: 0-7 (0 and 7 = Sunday)
# - Use only valid operators: * , - /
# - No invalid value combinations

# Install validated crontab
crontab new_cron.txt
```

_exec_
```bash
echo "0 2 * * * /home/user/backup.sh" | grep -E "^[0-9,*/-]+ [0-9,*/-]+ [0-9,*/-]+ [0-9,*/-]+ [0-9,*/-]+"
```

_output_
```bash
0 2 * * * /home/user/backup.sh
```

Always validate syntax before installing crontabs to prevent silent job failures.

- Invalid crontab syntax won't raise errors in some systems
- Use crontab -e in editor mode for immediate validation feedback
- crontab.guru is excellent for visualizing schedules

#### Full examples with explanations

```bash
# Run every minute (test only!)
* * * * * /path/to/command

# Run every hour at minute 0 (top of hour)
0 * * * * /path/to/command

# Run every 15 minutes
*/15 * * * * /path/to/command

# Run at 2 AM every day
0 2 * * * /path/to/backup.sh

# Run at 2:30 AM every day
30 2 * * * /path/to/backup.sh

# Run every 6 hours (midnight, 6am, noon, 6pm)
0 */6 * * * /path/to/maintenance.sh

# Run at 9 AM and 5 PM, Monday to Friday
0 9,17 * * 1-5 /path/to/report.sh

# Run on the 1st and 15th day of every month at midnight
0 0 1,15 * * /path/to/billing.sh

# Run every Sunday at 3 AM
0 3 * * 0 /path/to/weekly-task.sh

# Run every other hour on weekdays
0 */2 * * 1-5 /path/to/frequent-job.sh

# Run at 10, 20, 30, 40, 50 minutes every hour
10,20,30,40,50 * * * * /path/to/command
```

_exec_
```bash
echo "Examples loaded - use crontab.guru to visualize"
```

_output_
```bash
Examples loaded - use crontab.guru to visualize
```

Complete examples cover most common scheduling needs and can be adapted for your use cases.

- Always test script manually before scheduling
- Use absolute paths for all commands
- Redirect output to log files for monitoring
- Document all scheduled jobs in crontab

**Best practices:**

- Use crontab.guru to validate and visualize schedules
- Write clear comments in crontab explaining jobs
- Test scripts manually before adding to crontab
- Use absolute paths always
- Capture output to log files for troubleshooting

**Common errors:**

- **Invalid minute value (e.g., 0-61)**: Minute must be 0-59
- **Invalid hour value (e.g., 0-25)**: Hour must be 0-23 (24-hour format)

## Special Strings

Use predefined scheduling shortcuts for common intervals

### '@' Symbols (At Strings)

Special shortcuts for commonly used scheduling intervals

**Keywords:** special, strings, at, reboot, hourly, daily, weekly, monthly, yearly

#### Special string reference and usage

```text
# SPECIAL @ STRINGS - Shortcuts for Common Schedules

SPECIAL STRING  |  EQUIVALENT CRON   |  DESCRIPTION
────────────────┼───────────────────┼─────────────────────────────────
@reboot         |  N/A               |  Run once, at startup (reboot)
@hourly         |  0 * * * *        |  Run once every hour at minute 0
@daily          |  0 0 * * *        |  Run once every day at midnight
@midnight       |  0 0 * * *        |  Run once at midnight (same as @daily)
@weekly         |  0 0 * * 0        |  Run once weekly on Sunday at midnight
@monthly        |  0 0 1 * *        |  Run once monthly on 1st day at midnight
@yearly         |  0 0 1 1 *        |  Run once yearly on Jan 1st at midnight
@annually       |  0 0 1 1 *        |  Alias for @yearly


# ADVANTAGES OF SPECIAL STRINGS:
- More readable than cron time expressions
- Less prone to syntax errors
- Perfect for standard scheduling intervals
- Supported by all modern cron implementations
```

_exec_
```bash
echo "@daily /home/user/backup.sh" | crontab -
```

Special strings provide readable shortcuts for standard scheduling patterns.

- @reboot runs at system startup (not a specific time)
- @midnight and @daily are equivalent
- All other @strings have specific times (see equivalent column)

#### Using special strings in crontab

```bash
# Create crontab with special strings
cat > cron_schedule.txt << 'EOF'
# System maintenance tasks
@reboot /usr/local/bin/system-init.sh

# Log rotation (every hour)
@hourly /usr/sbin/logrotate /etc/logrotate.conf

# Database backup (daily at midnight)
@daily /home/user/backup-database.sh

# Weekly report (Sunday at midnight)
@weekly /home/user/generate-report.sh

# Monthly archive (1st of month at midnight)
@monthly /home/user/archive-old-files.sh

# Yearly audit (Jan 1st at midnight)
@yearly /home/user/annual-audit.sh
EOF

# Install the crontab
crontab cron_schedule.txt

# Verify installation
crontab -l
```

_exec_
```bash
crontab -l 2>/dev/null | grep "@" | head -3
```

_output_
```bash
@reboot /usr/local/bin/system-init.sh
@hourly /usr/sbin/logrotate /etc/logrotate.conf
@daily /home/user/backup-database.sh
```

Special strings make crontab files more maintainable and easier to understand.

- Mix special strings and normal cron syntax in same crontab
- Special strings are more readable for standard intervals
- Use regular cron syntax for non-standard schedules

### Special Variables and Environment

Set environment variables and use predefined variables in crontab

**Keywords:** variables, environment, shell, path, home, logname

#### Set environment variables in crontab

```bash
# Setting variables in crontab file
cat > crontab_with_env.txt << 'EOF'
# Environment variables for all jobs in this crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/username
LOGNAME=username
MAILTO=admin@example.com

# Optional: disable mail on successful execution
# CRONENV=prod

# Now define jobs that use these variables
0 2 * * * /home/username/scripts/backup.sh >> $HOME/logs/backup.log 2>&1

# Or with explicit paths
@daily /usr/local/bin/cleanup.sh >> /home/username/cron.log 2>&1
EOF

# Install crontab
crontab crontab_with_env.txt

# View installed crontab
crontab -l
```

_exec_
```bash
echo "Variables set at top of crontab file"
```

_output_
```bash
Variables set at top of crontab file
```

Environment variables must be set in crontab since cron doesn't load shell profiles.

- Set variables at the top of crontab file
- MAILTO controls email notifications (set empty to disable)
- HOME and PATH are especially important
- SHELL specifies which shell to use (/bin/bash, not /bin/sh)

#### Common environment gotchas and solutions

```bash
# GOTCHA 1: PATH not set correctly
# This FAILS - command not found
* * * * * mycommand

# This WORKS - absolute path
* * * * * /usr/bin/mycommand

# Or set PATH at top of crontab
PATH=/usr/local/bin:/usr/bin:/bin
* * * * * mycommand


# GOTCHA 2: HOME directory not set
# This FAILS if script uses ~
* * * * * ~/scripts/backup.sh

# This WORKS - explicit path
* * * * * /home/username/scripts/backup.sh

# Or set HOME in crontab
HOME=/home/username
* * * * * ~/scripts/backup.sh


# GOTCHA 3: Environment variables from .bashrc not loaded
# This FAILS - NO_COLOR not set
* * * * * /usr/bin/command

# This WORKS - source .bashrc first
* * * * * source ~/.bashrc; /usr/bin/command

# Better: set needed variables in crontab
NO_COLOR=1
* * * * * /usr/bin/command
```

_exec_
```bash
echo "Always test with: env -i bash -c 'your command'"
```

_output_
```bash
Always test with: env -i bash -c 'your command'
```

Testing with minimal environment reveals issues that will occur in cron jobs.

- Test cron jobs with: env -i bash -c 'your script'
- This simulates minimal cron environment
- Or use: /usr/bin/env -L bash -c 'your script'
- Always use absolute paths and set necessary variables

**Best practices:**

- Set SHELL, PATH, HOME, LOGNAME at top of crontab
- Use absolute paths for all commands and scripts
- Test scripts with minimal environment
- Document all environment requirements
- Set MAILTO to empty string if you want no notifications

**Common errors:**

- **/usr/bin/command: command not found**: Use absolute path or set PATH in crontab
- **HOME directory not found when using ~**: Set HOME variable in crontab or use absolute paths

## Scheduling Patterns

Real-world scheduling patterns and examples

### Common Scheduling Patterns

Practical patterns for typical system administration tasks

**Keywords:** patterns, examples, hourly, daily, weekly, monthly, common

#### Business hours and working day schedules

```bash
# Run during business hours (9 AM to 5 PM, Monday-Friday)
0 9-17 * * 1-5 /path/to/business-task.sh

# Run at start of business day (9 AM, weekdays)
0 9 * * 1-5 /path/to/daily-standup.sh

# Run at end of business day (5 PM, weekdays)
0 17 * * 1-5 /path/to/eod-report.sh

# Run every 2 hours during business hours
0 9,11,13,15,17 * * 1-5 /path/to/interim-check.sh

# Run every 30 minutes during business hours
*/30 9-17 * * 1-5 /path/to/frequent-task.sh

# Run weekday evenings (6 PM - 11 PM)
0 18-23 * * 1-5 /path/to/evening-task.sh

# Run weekend task (Saturday and Sunday)
0 10 * * 0,6 /path/to/weekend-task.sh
```

_exec_
```bash
echo "0 9-17 * * 1-5 command" | crontab -
```

Business schedule patterns align jobs with working hours.

- Hour 9-17 means 9 AM through 5 PM
- 1-5 for Monday through Friday
- 0,6 for Saturday and Sunday
- Adjust based on actual working hours and time zone

#### Backup and maintenance schedules

```bash
# Full backup every Sunday at 2 AM
0 2 * * 0 /path/to/full-backup.sh

# Incremental backup daily at 3 AM
0 3 * * * /path/to/incremental-backup.sh

# Database backup every 6 hours
0 */6 * * * /path/to/db-backup.sh

# Log rotation daily at midnight
0 0 * * * /usr/sbin/logrotate /etc/logrotate.conf

# Weekly maintenance (Sunday 4 AM)
0 4 * * 0 /path/to/weekly-maintenance.sh

# Monthly housekeeping (1st of month, 1 AM)
0 1 1 * * /path/to/monthly-cleanup.sh

# Quarterly archive (Jan 1, Apr 1, Jul 1, Oct 1 at 2 AM)
0 2 1 1,4,7,10 * /path/to/quarterly-archive.sh

# Yearly audit (Jan 1 at 3 AM)
0 3 1 1 * /path/to/annual-audit.sh
```

_exec_
```bash
echo "0 2 * * 0 /path/to/backup.sh" | crontab -
```

Backup schedules should stagger to avoid resource contention and database locks.

- Schedule backups during low-usage hours
- Incremental backups can be more frequent than full backups
- Rotate old backups to manage storage
- Monitor backup success with logging and alerts

#### Monitoring and notification schedules

```bash
# Health check every 5 minutes
*/5 * * * * /path/to/health-check.sh

# Monitor system every 10 minutes (all day)
*/10 * * * * /path/to/system-monitor.sh

# Check disk space every hour
0 * * * * /path/to/check-disk.sh

# Send daily report at 9 AM (weekdays)
0 9 * * 1-5 /path/to/daily-report.sh | mail -s "Daily Report" admin@example.com

# Weekly status report (Monday 8 AM)
0 8 * * 1 /path/to/weekly-status.sh | mail -s "Weekly Status" team@example.com

# Monitor critical service (every 15 minutes, 24/7)
*/15 * * * * /path/to/critical-service-check.sh

# Alert on failures (every 30 minutes if previous check failed)
*/30 * * * * if [ -f /tmp/service-down ]; then /path/to/alert.sh; fi
```

_exec_
```bash
echo "*/5 * * * * /path/to/check.sh" | crontab -
```

Monitoring jobs run frequently but should be optimized to minimize overhead.

- Balance frequency with resource usage
- Use lock files to prevent overlapping runs
- Log all monitoring results
- Set alerts for critical failures

### Advanced Scheduling Patterns

Complex scheduling for specific needs

**Keywords:** advanced, complex, patterns, staggered, random, load, balancing

#### Staggered and load-balanced schedules

```bash
# Stagger backups across multiple servers
# Server 1: runs at :00
0 2 * * * /path/to/backup.sh

# Server 2: runs at :15
15 2 * * * /path/to/backup.sh

# Server 3: runs at :30
30 2 * * * /path/to/backup.sh

# Server 4: runs at :45
45 2 * * * /path/to/backup.sh


# Load balanced hourly jobs (4 servers, evenly distributed)
# Server 1: run at :00
0 * * * * /path/to/hourly-job.sh

# Server 2: run at :15
15 * * * * /path/to/hourly-job.sh

# Server 3: run at :30
30 * * * * /path/to/hourly-job.sh

# Server 4: run at :45
45 * * * * /path/to/hourly-job.sh


# Rotate tasks across different times
# Task A: Monday, Wednesday, Friday
0 2 * * 1,3,5 /path/to/task-a.sh

# Task B: Tuesday, Thursday
0 2 * * 2,4 /path/to/task-b.sh

# Task C: Sunday and Saturday
0 2 * * 0,6 /path/to/task-c.sh
```

_exec_
```bash
echo "Staggered schedules prevent resource bottlenecks"
```

_output_
```bash
Staggered schedules prevent resource bottlenecks
```

Staggered patterns distribute resource-intensive tasks across time to maintain system performance.

- Stagger when running same task on multiple servers
- Distribute load across minutes if possible
- Consider time zone differences across servers
- Monitor system resources during peak schedule times

#### Conditional and wrapper-based scheduling

```bash
# Run only if previous job completed (using lock file)
*/5 * * * * [ ! -f /tmp/long-job.lock ] && /path/to/frequent-job.sh

# Run with fallback if primary command fails
0 2 * * * /path/to/primary-backup.sh || /path/to/fallback-backup.sh

# Run with dependency check
0 * * * * [ -x /usr/bin/rsync ] && /path/to/rsync-backup.sh

# Run only on specific conditions (e.g., low load)
*/10 * * * * [ $(uptime | awk -F'average:' '{print $2}' | awk '{print $1}' | cut -d. -f1) -lt 2 ] && /path/to/async-task.sh

# Run with timeout to prevent hanging
0 2 * * * timeout 300 /path/to/backup.sh || echo "Backup timed out!"

# Run with retry logic (wrapper script)
0 * * * * /path/to/retry-wrapper.sh 3 /path/to/unreliable-command.sh

# Run with output capture and error handling
0 2 * * * {
  /path/to/backup.sh 2>&1
  [ $? -eq 0 ] && echo "Success" || echo "Failed" | mail -s "Backup Error" admin@example.com
}
```

_exec_
```bash
echo "[ ! -f /tmp/lock ] && /path/to/command.sh"
```

Conditional patterns add robustness and prevent cascading failures.

- Use lock files to prevent overlapping executions
- Always capture errors and log results
- Use timeout for commands that might hang
- Test complex schedules thoroughly before deployment

## Crontab Management

Edit, view, backup, and manage crontab files

### Editing and Installing Crontabs

Methods to safely edit and install crontab files

**Keywords:** edit, install, crontab, editor, file, backup

#### Edit crontab using the interactive editor

```bash
# Edit current user's crontab
crontab -e

# Edit another user's crontab (requires root)
sudo crontab -e -u username

# Specify which editor to use
EDITOR=vim crontab -e
EDITOR=nano crontab -e
EDITOR=emacs crontab -e

# Change default editor permanently
export EDITOR=vim
echo 'export EDITOR=vim' >> ~/.bashrc

# View crontab before saving (in editor)
# Editor opens temp file - make changes and save
# Cron validates syntax when file is saved
# If syntax is invalid, you'll be asked to re-edit or discard

# Backup current crontab before editing
crontab -l > crontab.backup
crontab -e  # Make changes safely
```

_exec_
```bash
echo "crontab -e to edit interactively"
```

_output_
```bash
crontab -e to edit interactively
```

The -e flag opens an interactive editor with validation on save for safe editing.

- crontab -e is the recommended method (validates syntax)
- Default editor determined by EDITOR or VISUAL env var
- Any syntax errors prevent installation
- Always backup before making changes

#### Install crontab from file

```bash
# Create a crontab file
cat > my_crontab << 'EOF'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
HOME=/home/user

# Example jobs
0 2 * * * /home/user/backup.sh
0 0 * * 0 /home/user/weekly-task.sh
EOF

# Install it as current user's crontab
crontab my_crontab

# Install for another user (requires root)
sudo crontab -u username my_crontab

# Replace existing crontab
crontab my_crontab  # This overwrites current crontab

# Add to existing crontab (append instead of replace)
crontab -l > current_crontab.txt
cat additional_jobs.txt >> current_crontab.txt
crontab current_crontab.txt

# Verify installation
crontab -l
```

_exec_
```bash
echo "0 2 * * * /path/to/job.sh" > cron.txt && crontab cron.txt
```

Install crontab files for programmatic configuration and automation.

- crontab <file> replaces entire crontab
- crontab is read entirely before installation
- Syntax errors prevent installation completely
- Always backup before installing new crontab

### List, Delete, and Manage Crontabs

View and remove scheduled jobs

**Keywords:** list, delete, remove, view, manage, display

#### View and manage crontab entries

```bash
# List current user's crontab
crontab -l

# List another user's crontab (requires root)
sudo crontab -l -u username

# Count number of cron jobs
crontab -l | grep -c "^[^#]"

# List non-comment lines only
crontab -l | grep "^[^#]"

# Find specific job
crontab -l | grep "backup"

# List all system crontabs
sudo cat /etc/crontab

# List all user crontabs in /var/spool/cron
sudo ls -la /var/spool/cron/crontabs/

# View specific user's crontab file
sudo cat /var/spool/cron/crontabs/username
```

_exec_
```bash
crontab -l 2>/dev/null | head -5
```

_output_
```bash
# Comments start with #
0 2 * * * /home/user/backup.sh
```

List commands show scheduled jobs without opening editor.

- crontab -l shows current user's crontab
- grep filters output to show specific jobs
- Lines starting with
- System-wide crontabs are in /etc/cron.d/ and /etc/crontab

#### Delete and remove crontabs

```bash
# DANGER: Remove entire crontab for current user
crontab -r

# DANGER: Remove entire crontab for specific user (requires root)
sudo crontab -r -u username

# Safe way: backup first, then remove
crontab -l > crontab.backup
crontab -r

# Remove specific job without deleting all jobs
crontab -l | grep -v "pattern-to-remove" | crontab -
# Example: remove backup job, keep others
crontab -l | grep -v "backup" | crontab -

# Remove all jobs but keep environment variables
crontab -l | grep "^[A-Z]" | crontab -

# Disable job by commenting it (safer than deleting)
crontab -e  # Then add # at start of line

# Remove from system-wide cron
sudo rm /etc/cron.d/jobname
sudo rm /etc/cron.daily/myscript
```

_exec_
```bash
crontab -l | grep -v "backup" | crontab -
```

Safe removal techniques preserve other jobs while removing only what's needed.

- Always backup before removing with crontab -r
- Use grep to filter and remove specific jobs safely
- Commenting is safer than deleting for temporary disabling
- System crontabs require root access to modify

### Advanced Crontab Techniques

Backup, restore, and automate crontab management

**Keywords:** advanced, backup, restore, script, automate, deploy

#### Backup and restore crontabs

```bash
# Backup current crontab before changes
crontab -l > ~/crontab.backup.$(date +%Y%m%d)

# Backup all user crontabs (requires root)
sudo for user in $(cut -f1 -d: /etc/passwd); do
  crontab -l -u "$user" > /backups/crontab_$user.backup 2>/dev/null
done

# Restore from backup
crontab ~/crontab.backup.20250228

# Compare current with backup
diff <(crontab -l) <(cat ~/crontab.backup.20250228)

# Version control crontab
crontab -l > crontab.txt
git add crontab.txt
git commit -m "Update crontab: add daily backup job"

# Deploy crontab from version control
git pull
crontab crontab.txt
```

_exec_
```bash
crontab -l > crontab.backup.$(date +%Y%m%d)
```

Backup and version control ensure safe crontab management and recovery.

- Timestamp backups with date for tracking changes
- Keep backups in version control for history
- Test restored crontabs before deploying to production
- Document all changes in commit messages

#### Script jobs with logging and error handling

```bash
# Create robust cron script with logging
cat > /usr/local/bin/cron-backup.sh << 'EOF'
#!/bin/bash
set -e  # Exit on error

# Configuration
BACKUP_DIR="/backups"
LOG_FILE="/var/log/backup.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
HOSTNAME=$(hostname)

# Log function
log() {
  echo "[${DATE}] ${HOSTNAME}: $1" >> "${LOG_FILE}"
}

# Error handling
error_exit() {
  log "ERROR: $1"
  echo "ERROR: $1" | mail -s "Backup Failed on ${HOSTNAME}" admin@example.com
  exit 1
}

# Create backup
log "Starting backup..."
tar -czf "${BACKUP_DIR}/backup-$(date +%Y%m%d).tar.gz" /home || error_exit "Backup failed"
log "Backup completed successfully"

# Cleanup old backups (keep 7 days)
find "${BACKUP_DIR}" -name "backup-*.tar.gz" -mtime +7 -delete

log "Cleanup completed"
EOF

chmod +x /usr/local/bin/cron-backup.sh

# Add to crontab with logging
crontab -e
# Add: 0 2 * * * /usr/local/bin/cron-backup.sh >> /var/log/cron.log 2>&1
```

_exec_
```bash
chmod +x /usr/local/bin/cron-backup.sh
```

Robust scripts include logging, error handling, and notifications for production reliability.

- Always include error handling (set -e, exit codes)
- Log to file for auditing and debugging
- Send error notifications to admin
- Use absolute paths for all commands
- Test scripts thoroughly before scheduling

**Best practices:**

- Always backup crontab before making changes
- Use crontab -e for safe interactive editing
- Test scripts manually before scheduling
- Keep crontab in version control
- Log all job output for debugging
- Set up error notifications for critical jobs

**Common errors:**

- **crontab: command not found**: Ensure you're using crontab command, not cron
- **Permission denied when editing crontab**: Check /etc/cron.allow and /etc/cron.deny files

## Advanced Scheduling

Advanced cron features and optimization techniques

### Ranges, Steps, and Lists

Master complex scheduling with ranges, steps, and value lists

**Keywords:** ranges, steps, lists, intervals, values, complex

#### Using ranges and step values

```text
# RANGES (using -)
# Run every minute from 9 AM to 5 PM
* 9-17 * * * /path/to/command

# Run on weekdays (Monday-Friday)
0 0 * * 1-5 /path/to/command

# Run first 7 days of each month
0 0 1-7 * * /path/to/command

# Run June, July, August only
0 0 * 6-8 * /path/to/command


# STEPS/INTERVALS (using /)
# Every 5 minutes
*/5 * * * * /path/to/command

# Every 2 hours
0 */2 * * * /path/to/command

# Every 3 days
0 0 */3 * * /path/to/command

# Every second month (Jan, Mar, May, Jul, Sep, Nov)
0 0 1 */2 * /path/to/command

# Every 15 minutes between 9-17 (9:00, 9:15, 9:30, ..., 17:00)
*/15 9-17 * * * /path/to/command

# Every 4 hours starting at 2 AM (2, 6, 10, 14, 18, 22)
0 2-23/4 * * * /path/to/command


# STEP WITH RANGE
# Start at minute 10, every 15 minutes (10, 25, 40, 55)
10-59/15 * * * * /path/to/command

# Start at hour 8, every 3 hours (8, 11, 14, 17, 20, 23)
0 8-23/3 * * * /path/to/command

# Every 2 days starting from day 1 (1, 3, 5, 7, ...)
0 0 1-31/2 * * /path/to/command
```

_exec_
```bash
echo "*/5 * * * * = every 5 minutes"
```

_output_
```bash
*/5 * * * * = every 5 minutes
```

Ranges and steps create flexible scheduling patterns for complex intervals.

- Ranges use hyphen: min-max
- Steps use slash: */interval or min-max/interval
- Steps count from field minimum (minutes from 0)
- Ranges and steps can combine in one field

#### Using lists and comma-separated values

```bash
# RUN AT SPECIFIC HOURS
# Run at 8 AM, 12 PM (noon), and 5 PM
0 8,12,17 * * * /path/to/command

# Run at 6 AM and 6 PM
0 6,18 * * * /path/to/command

# Run at :00, :15, :30, :45 (every 15 minutes)
0,15,30,45 * * * * /path/to/command


# RUN ON SPECIFIC DAYS OF WEEK
# Run Monday, Wednesday, Friday
0 0 * * 1,3,5 /path/to/command

# Run Saturday, Sunday, Monday
0 0 * * 6,0,1 /path/to/command


# RUN ON SPECIFIC DATES
# Run on 1st, 10th, 20th of month
0 0 1,10,20 * * /path/to/command

# Run on 15th and last day of month (1st of next)
# Note: This is tricky - need separate job for last day
0 0 15 * * /path/to/command
0 0 1 * * [ "$(date +\%d)" != "01" ] && /path/to/command


# RUN IN SPECIFIC MONTHS
# Run in January, April, July, October
0 0 1 1,4,7,10 * /path/to/command

# Run in summer (June, July, August)
0 0 * 6,7,8 * /path/to/command


# COMBINED LISTS AND RANGES
# Run on specific hours and specific days
0 8,14,20 * * 1-5 /path/to/command

# Run at multiple times on multiple days
0,30 9,12,15 * * 1-5 /path/to/command
```

_exec_
```bash
echo "0 8,12,17 * * * /path/to/command"
```

_output_
```bash
0 8,12,17 * * * /path/to/command
```

Lists (comma-separated values) specify exact times and dates for flexible scheduling.

- Separators are commas with no spaces
- List all values individually: 1,2,3 (not 1-3 in list form)
- Can combine lists with ranges: 1,3-5,7 (equals 1,3,4,5,7)
- Lists work for all fields: minutes, hours, days, months, weekdays

### Environment and Optimization

Environment variables, best practices, and performance optimization

**Keywords:** environment, variables, optimization, performance, best, practices

#### Set comprehensive environment in crontab

```bash
# COMPLETE CRONTAB WITH ENVIRONMENT SETUP
cat > crontab_optimized << 'EOF'
# ============================================
# ENVIRONMENT CONFIGURATION
# ============================================

# Shell to use (bash, not sh)
SHELL=/bin/bash
BASH_ENV=/home/username/.bashrc

# PATH (critical for command discovery)
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# Home directory (some scripts use~)
HOME=/home/username

# Current user
LOGNAME=username
USER=username

# Mail configuration (empty = no mail, valid email = send notifications)
MAILTO=admin@example.com

# Language and locale
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8

# Optional: Application-specific variables
APP_ENV=production
NODE_ENV=production
DEBUG=0

# ============================================
# SCHEDULED JOBS
# ============================================

# System maintenance
@reboot /usr/local/bin/system-init.sh >> /var/log/cron-init.log 2>&1

# Backups
0 2 * * * /home/username/scripts/backup.sh >> /var/log/backup.log 2>&1

# Database maintenance
0 3 * * 0 /home/username/scripts/db-maintenance.sh >> /var/log/db-maint.log 2>&1

# Log rotation
0 0 * * * /usr/sbin/logrotate /etc/logrotate.conf >> /var/log/logrotate.log 2>&1
EOF

crontab crontab_optimized
```

_exec_
```bash
echo "SHELL=/bin/bash PATH=... HOME=..."
```

_output_
```bash
SHELL=/bin/bash PATH=... HOME=...
```

Proper environment setup ensures scripts work correctly in cron's limited environment.

- Set variables at top of crontab file
- SHELL should be /bin/bash, not /bin/sh
- PATH is critical - include all directories where commands exist
- MAILTO controls email notifications

#### Performance optimization and load management

```bash
# PERFORMANCE CONSIDERATIONS

# 1. Stagger resource-intensive jobs
# Don't run everything at midnight
0 1 * * * /path/to/job1.sh    # 1 AM
0 2 * * * /path/to/job2.sh    # 2 AM
0 3 * * * /path/to/job3.sh    # 3 AM
0 4 * * * /path/to/job4.sh    # 4 AM


# 2. Add random delay for distributed jobs
# Useful when same job runs on many servers
0 2 * * * sleep $((RANDOM \% 600)) && /path/to/backup.sh


# 3. Limit job concurrency with lock files
# Use wrapper script to prevent overlapping
*/5 * * * * /path/to/locked-job-wrapper.sh /path/to/actual-job.sh


# 4. Use -nice to lower priority for background jobs
0 2 * * * nice -n 19 /path/to/low-priority-job.sh


# 5. Monitor system before running expensive tasks
*/10 * * * * [ $(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | cut -d. -f1) -lt 8 ] && /path/to/compute-intensive.sh


# 6. Redirect output to avoid mail daemon overhead
0 2 * * * /path/to/job.sh > /dev/null 2>&1  # Discard output
0 2 * * * /path/to/job.sh >> /var/log/jobs.log 2>&1  # Log to file


# 7. Break large jobs into smaller pieces
# Process in batches instead of all at once
0 2 * * * /path/to/process-batch.sh 1
0 3 * * * /path/to/process-batch.sh 2
0 4 * * * /path/to/process-batch.sh 3
```

_exec_
```bash
echo "Stagger jobs to prevent resource bottlenecks"
```

_output_
```bash
Stagger jobs to prevent resource bottlenecks
```

Optimization prevents system load spikes and ensures consistent performance.

- Stagger heavy workloads across multiple hours
- Monitor system load before running resource-intensive jobs
- Limit concurrency with lock files to prevent overlapping
- Use nice for background tasks
- Log output to files instead of relying on mail

**Best practices:**

- Test complex schedules with crontab.guru
- Use absolute paths for all commands
- Redirect output to log files
- Set environment variables at top of crontab
- Stagger resource-intensive jobs
- Monitor system load before scheduling heavy workloads
- Use lock files to prevent concurrent execution

**Common errors:**

- **Complex range syntax incorrect**: Verify range format (min-max/step) with crontab.guru
- **Day-of-month conflicts with day-of-week**: If both specified, cron uses OR logic (either one matches)

## Tips & Troubleshooting

Best practices, common issues, and debugging cron jobs

### Best Practices

Essential practices for reliable cron job scheduling

**Keywords:** best, practices, reliable, production, guidelines

#### Production-ready cron job checklist

```bash
# PRODUCTION CRON JOB REQUIREMENTS CHECKLIST

# ✓ 1. Use absolute paths for all commands
# BAD:
* * * * * backup.sh

# GOOD:
* * * * * /usr/local/bin/backup.sh


# ✓ 2. Set working directory explicitly
* * * * * cd /home/user && /usr/local/bin/backup.sh
# OR
* * * * * /usr/local/bin/backup.sh -d /var/data


# ✓ 3. Log output to files (not relying on mail)
# BAD:
0 2 * * * /path/to/backup.sh

# GOOD:
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1


# ✓ 4. Capture exit codes for debugging
# GOOD:
0 2 * * * {
  /path/to/backup.sh
  EXIT_CODE=$?
  echo "Backup completed with exit code: $EXIT_CODE" >> /var/log/backup.log
  [ $EXIT_CODE -ne 0 ] && echo "Backup failed!" | mail -s "Alert" admin@example.com
} 2>&1 | tee -a /var/log/backup.log


# ✓ 5. Include timestamp in logs
# BAD:
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1

# GOOD:
0 2 * * * echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting backup" >> /var/log/backup.log && /path/to/backup.sh >> /var/log/backup.log 2>&1


# ✓ 6. Protect against overlapping runs
# Use lock file pattern:
*/5 * * * * /path/to/locked-wrapper.sh /path/to/actual-job.sh


# ✓ 7. Document all cron jobs in crontab
# GOOD crontab:
# Daily backup at 2 AM
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1

# Weekly report (Sunday, 8 AM)
0 8 * * 0 /path/to/weekly-report.sh >> /var/log/reports.log 2>&1

# Verify cron was actually installed correctly
crontab -l
```

_exec_
```bash
crontab -l | head -10
```

_output_
```bash
# Backup jobs
0 2 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1
```

Following best practices ensures reliable job execution and easier debugging.

- Always test scripts manually before scheduling
- Include comments explaining purpose and frequency
- Log with timestamps for easier analysis
- Implement error handling and notifications
- Review logs regularly for job failures

#### Error handling and debugging strategies

```bash
# ROBUST SCRIPT WITH ERROR HANDLING
cat > /usr/local/bin/robust-backup.sh << 'EOF'
#!/bin/bash
set -eEu  # Exit on error, undefined vars, pipe errors
shopt -s pipefail

# Configuration
BACKUP_DIR="/backups"
LOG_FILE="/var/log/backup.log"
LOCK_FILE="/tmp/backup.lock"
MAX_RUNTIME=3600  # 1 hour

# Logging function
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}

# Error handler
error_exit() {
  local line_no=$1
  local exit_code=$2
  log "ERROR at line $line_no (exit code: $exit_code)"
  rm -f "$LOCK_FILE"
  echo "Backup failed at line $line_no" | mail -s "Backup ERROR" admin@example.com
  exit 1
}

# Cleanup on exit
trap 'error_exit ${LINENO} $?' ERR

# Prevent concurrent runs
if [ -f "$LOCK_FILE" ]; then
  log "Previous backup still running (lock file exists)"
  exit 1
fi
touch "$LOCK_FILE"
trap 'rm -f "$LOCK_FILE"' EXIT

# Main backup logic
log "Backup started"
tar -czf "$BACKUP_DIR/backup-$(date +%Y%m%d_%H%M%S).tar.gz" /home/user/ || {
  log "Backup creation failed"
  exit 1
}

# Cleanup old backups
find "$BACKUP_DIR" -name "backup-*.tar.gz" -mtime +7 -delete
log "Backup completed successfully"
EOF

chmod +x /usr/local/bin/robust-backup.sh

# Add to crontab
echo "0 2 * * * timeout 4000 /usr/local/bin/robust-backup.sh" | crontab -
```

_exec_
```bash
chmod +x /usr/local/bin/robust-backup.sh
```

Robust error handling prevents cascading failures and aids in debugging.

- Use set -e, -E, -u, -o pipefail for strict error handling
- Implement trap handlers for cleanup
- Always remove lock files on exit
- Log detailed error information
- Send notifications for critical failures

### Debugging Common Issues

Troubleshoot and fix common cron problems

**Keywords:** debugging, troubleshooting, issues, problems, solutions, errors

#### Common cron problems and solutions

```bash
# PROBLEM 1: Job never executes
# Symptoms: Scheduled time passes, nothing happens
# Solutions:

# Check 1: Cron daemon is running
systemctl status cron

# Check 2: Verify crontab is installed
crontab -l

# Check 3: Verify system time (jobs scheduled for past times won't run)
date
timedatectl

# Check 4: Check cron logs (varies by system)
# On Debian/Ubuntu:
grep CRON /var/log/syslog | tail -20
# On CentOS/RHEL:
tail -f /var/log/cron

# Check 5: Verify file permissions (user must have read permission)
ls -la /var/spool/cron/crontabs/username

# Check 6: Verify user has cron access
cat /etc/cron.allow      # If exists, user must be listed
cat /etc/cron.deny       # If exists, user must NOT be listed


# PROBLEM 2: Job runs but doesn't work (environment issues)
# Symptoms: Manual execution works, cron execution fails
# Solutions:

# Create test script to check environment
cat > test-env.sh << 'TESTEOF'
#!/bin/bash
{
  echo "User: $(whoami)"
  echo "Home: $HOME"
  echo "Path: $PATH"
  echo "Shell: $SHELL"
  echo "PWD: $PWD"
  which python3
  python3 --version
} > /tmp/cron-env-test.log 2>&1
TESTEOF

# Schedule it
echo "* * * * * /path/to/test-env.sh" | crontab -
# Wait a minute, then check:
cat /tmp/cron-env-test.log

# Fix: Set environment variables in crontab
crontab -e
# Add at top:
# SHELL=/bin/bash
# PATH=/usr/local/bin:/usr/bin:/bin
# HOME=/home/username


# PROBLEM 3: Permission denied errors
# Symptoms: Cron log shows "Permission denied"
# Solutions:

# Check script permissions
ls -la /path/to/script.sh
# Fix: Make executable
chmod +x /path/to/script.sh

# Check user permissions for target files
ls -la /var/log/backup.log
# Fix: Change permissions or ownership
sudo chown username /var/log/backup.log


# PROBLEM 4: Command not found in cron
# Symptoms: Works manually, "command not found" in cron
# Solutions:

# Use ABSOLUTE PATHS
# BAD:
* * * * * backup.sh
# GOOD:
* * * * * /home/user/backup.sh

# Or use full path with which:
which backup.sh  # Returns: /usr/local/bin/backup.sh
* * * * * /usr/local/bin/backup.sh


# PROBLEM 5: Job runs at wrong time
# Symptoms: Job runs at unexpected time
# Solutions:

# Check system time zone
date
timedatectl
# Verify cron schedule with crontab.guru

# Remember: DST changes affect cron times
# If changed timezone, reboot may be needed
sudo reboot
```

_exec_
```bash
systemctl status cron && echo "Cron daemon is running"
```

_output_
```bash
Active: active (running) since Fri 2025-02-28 10:00:00 UTC
Cron daemon is running
```

Systematic checking helps identify the root cause of cron job failures.

- Start with basic checks: daemon running, crontab installed
- Check both syslog and /var/log/cron
- Test with minimal environment: env -i bash -c 'command'
- Always use absolute paths
- Set environment variables in crontab

#### Monitoring and logging cron jobs

```bash
# SETUP MONITORING FOR CRON JOBS

# 1. View cron logs (system-wide)
# On Debian/Ubuntu (older):
grep CRON /var/log/syslog | tail -50

# On Debian/Ubuntu (modern with journald):
journalctl -u cron --since "2 hours ago"

# On CentOS/RHEL:
tail -100 /var/log/cron

# 2. Monitor cron log in real-time
journalctl -u cron -f  # Follow mode
tail -f /var/log/cron


# 3. Filter cron logs by user
journalctl -u cron | grep username
grep "username" /var/log/cron


# 4. Check for failed jobs in last 24 hours
journalctl -u cron -S "24 hours ago" | grep -i "error\|fail\|exit"


# 5. Count job executions per hour
grep "username" /var/log/cron | cut -d: -f1-3 | sort | uniq -c


# 6. Verify job last execution time
stat /path/to/output/file  # Check modification time
ls -la /path/to/output/file


# 7. Create wrapper script with comprehensive logging
cat > /usr/local/bin/logging-wrapper.sh << 'EOF'
#!/bin/bash
SCRIPT="$1"
LOG_DIR="/var/log/cron-jobs"
LOG_FILE="$LOG_DIR/$(basename "$SCRIPT" .sh).log"

mkdir -p "$LOG_DIR"

{
  echo "========================================"
  echo "Started: $(date '+%Y-%m-%d %H:%M:%S')"
  echo "User: $(whoami)"
  echo "Command: $SCRIPT"
  echo "========================================"

  "$SCRIPT"
  EXIT_CODE=$?

  echo "========================================"
  echo "Completed: $(date '+%Y-%m-%d %H:%M:%S')"
  echo "Exit code: $EXIT_CODE"
  echo "========================================"

  [ $EXIT_CODE -ne 0 ] && echo "FAILED: $SCRIPT" || echo "SUCCESS: $SCRIPT"
} >> "$LOG_FILE" 2>&1

exit $EXIT_CODE
EOF

chmod +x /usr/local/bin/logging-wrapper.sh

# Use in crontab:
# 0 2 * * * /usr/local/bin/logging-wrapper.sh /path/to/backup.sh
```

_exec_
```bash
journalctl -u cron --since "1 hour ago" | tail -20
```

_output_
```bash
Feb 28 14:05:01 hostname CRON[12345]: (username) CMD (/path/to/backup.sh)
Feb 28 14:05:05 hostname CRON[12345]: (username) CMDEND (/path/to/backup.sh)
```

Regular log monitoring helps identify issues early and verify job execution.

- Check both journalctl (systemd) and /var/log/cron
- Create wrapper scripts for detailed logging
- Monitor log files for errors and patterns
- Archive and rotate logs to manage disk space
- Set up alerts for failed jobs using grep and mail

**Best practices:**

- Always test scripts manually before scheduling
- Use absolute paths for all commands
- Redirect output to log files with timestamps
- Implement error handling and notifications
- Monitor cron logs regularly
- Test with minimal environment (env -i bash -c)
- Document all scheduled jobs
- Review and audit cron jobs quarterly

**Common errors:**

- **No such file or directory**: Use absolute paths, verify file exists with full path
- **command not found (while works manually)**: Set PATH in crontab or use absolute paths
- **Job runs but with wrong environment**: Set environment variables at top of crontab (SHELL, PATH, HOME)
