Post

Linux Job Scheduling Guide with Cheat Sheet

Quick Navigation

Introduction

Task automation is essential for effective Linux system administration. This guide covers cron, at, and systemd timers with a comprehensive cheat sheet for all common scheduling scenarios.

Cron Cheat Sheet

Field Format

1
2
3
4
5
6
7
* * * * * command
│ │ │ │ │
│ │ │ │ └─── Day of Week (0-7, Sun=0 or 7)
│ │ │ └──────── Month (1-12)
│ │ └───────────── Day of Month (1-31)
│ └────────────────── Hour (0-23)
└─────────────────────── Minute (0-59)

Special Characters

  • * - Any value
  • , - List (e.g., 1,15 = 1st and 15th)
  • - - Range (e.g., 9-17 = 9 AM to 5 PM)
  • / - Step (e.g., */5 = every 5 units)

Common Time Patterns

Every X Minutes

1
2
3
4
*/5 * * * *    # Every 5 minutes
*/10 * * * *   # Every 10 minutes
*/15 * * * *   # Every 15 minutes
*/30 * * * *   # Every 30 minutes

Hourly Variations

1
2
3
4
5
6
0 * * * *      # Every hour (on the hour)
30 * * * *     # Every hour at 30 minutes past
0 */2 * * *    # Every 2 hours
0 */3 * * *    # Every 3 hours
0 */6 * * *    # Every 6 hours
0 0,12 * * *   # Twice daily (midnight and noon)

Daily Schedules

1
2
3
4
5
0 0 * * *      # Daily at midnight
0 2 * * *      # Daily at 2 AM
0 9 * * *      # Daily at 9 AM
30 15 * * *    # Daily at 3:30 PM
0 0,12 * * *   # Twice daily (midnight and noon)

Weekly Patterns

1
2
3
4
0 0 * * 0      # Weekly on Sunday at midnight
0 0 * * 1      # Weekly on Monday at midnight
0 9 * * 1-5    # Weekdays at 9 AM
0 0 * * 6      # Weekly on Saturday at midnight

Monthly Schedules

1
2
3
4
0 0 1 * *      # First day of month at midnight
0 0 15 * *     # 15th of month at midnight
0 0 1,15 * *   # 1st and 15th at midnight
0 0 L * *      # Last day of month (not all cron versions)

Quarterly and Yearly

1
2
3
4
0 0 1 */3 *    # First day of every quarter
0 0 1 1,4,7,10 *  # First day of each quarter (Jan, Apr, Jul, Oct)
0 0 1 1 *      # Annually on January 1st
0 0 25 12 *    # Annually on December 25th

Business Hours

1
2
3
4
0 9-17 * * 1-5    # Every hour, 9 AM-5 PM, weekdays
*/30 9-17 * * 1-5 # Every 30 min, 9 AM-5 PM, weekdays
0 9 * * 1-5       # Weekdays at 9 AM
0 18 * * 1-5      # Weekdays at 6 PM

Complex Patterns

1
2
3
4
0 */2 * * 1-5     # Every 2 hours on weekdays
*/15 9-17 * * *   # Every 15 min during 9 AM-5 PM
0 0 * * 1,3,5     # Mon, Wed, Fri at midnight
30 7 1,15 * *     # 1st and 15th at 7:30 AM

Special Keywords

1
2
3
4
5
6
7
8
@reboot         # Run at startup
@yearly         # 0 0 1 1 *
@annually       # Same as @yearly
@monthly        # 0 0 1 * *
@weekly         # 0 0 * * 0
@daily          # 0 0 * * *
@midnight       # Same as @daily
@hourly         # 0 * * * *

Common Cron Commands

1
2
3
4
5
crontab -e           # Edit crontab
crontab -l           # List crontab
crontab -r           # Remove crontab
crontab -u user -e   # Edit another user's crontab (root only)
crontab -u user -l   # List another user's crontab (root only)

Sub-Minute Tasks (15 seconds)

Problem

Cron’s minimum interval is 1 minute. For tasks requiring execution every 15 seconds, you need alternative approaches.

Solution 1: Cron with Sleep Loop (Simple)

1
2
3
4
5
# Run every minute, execute 4 times with 15-second intervals
* * * * * /path/to/script.sh
* * * * * sleep 15; /path/to/script.sh
* * * * * sleep 30; /path/to/script.sh
* * * * * sleep 45; /path/to/script.sh

Or create a wrapper script:

1
2
3
4
5
6
#!/bin/bash
# /usr/local/bin/15sec-wrapper.sh
for i in {1..4}; do
    /path/to/your-script.sh &
    sleep 15
done

Then in crontab:

1
* * * * * /usr/local/bin/15sec-wrapper.sh

Create a timer unit with OnUnitActiveSec:

/etc/systemd/system/mytask.timer

1
2
3
4
5
6
7
8
9
10
[Unit]
Description=Run task every 15 seconds

[Timer]
OnBootSec=15sec
OnUnitActiveSec=15sec
AccuracySec=1sec

[Install]
WantedBy=timers.target

/etc/systemd/system/mytask.service

1
2
3
4
5
6
[Unit]
Description=My 15-second task

[Service]
Type=oneshot
ExecStart=/path/to/script.sh

Enable and start:

1
2
3
4
systemctl daemon-reload
systemctl enable mytask.timer
systemctl start mytask.timer
systemctl status mytask.timer

Solution 3: Watch Command

1
watch -n 15 /path/to/script.sh

Run in background:

1
nohup watch -n 15 /path/to/script.sh &

Solution 4: While Loop as Service

Create a persistent service:

/etc/systemd/system/continuous-task.service

1
2
3
4
5
6
7
8
9
10
[Unit]
Description=Continuous 15-second task

[Service]
Type=simple
ExecStart=/usr/local/bin/continuous-runner.sh
Restart=always

[Install]
WantedBy=multi-user.target

/usr/local/bin/continuous-runner.sh

1
2
3
4
5
#!/bin/bash
while true; do
    /path/to/your-script.sh
    sleep 15
done

Solution Comparison

Method Pros Cons Best For
Cron + Sleep Simple, no extra setup Multiple cron entries, less precise Quick solutions
Systemd Timer Precise, integrated logging Requires systemd Production systems
Watch Simple one-liner Must manage background process Testing/development
While Loop Service Reliable, auto-restart Slightly more complex Critical tasks

At Command Reference

Time Formats

1
2
3
4
5
6
7
8
9
10
11
at now + 5 minutes
at now + 2 hours
at now + 3 days
at 10:00 PM
at 14:30
at midnight
at noon
at tomorrow
at next week
at 4:30 PM March 20
at 16:30 2025-03-20

Usage Examples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Interactive
at 10:00 PM
at> /home/user/backup.sh
at> <Ctrl+D>

# From file
at -f script.txt 10:00 PM

# List jobs
atq

# Remove job
atrm 2

# View job details
at -c 2

Systemd Timer Examples

Realtime Timer (Like Cron)

1
2
3
4
[Timer]
OnCalendar=*-*-* 09:00:00    # Daily at 9 AM
OnCalendar=Mon *-*-* 14:00:00 # Mondays at 2 PM
OnCalendar=*-*-01 00:00:00   # First of month

Monotonic Timer (Event-based)

1
2
3
4
[Timer]
OnBootSec=5min              # 5 min after boot
OnActiveSec=10min           # 10 min after activation
OnUnitActiveSec=15sec       # 15 sec after last run

Systemd Commands

1
2
3
4
5
systemctl list-timers --all          # List all timers
systemctl start timer.name           # Start timer
systemctl enable timer.name          # Enable at boot
systemctl status timer.name          # Check status
journalctl -u service.name           # View logs

Full Documentation

Understanding Cron

Derived from the Greek word chronos (time), cron provides a robust framework for recurring task execution through the crond daemon and crontab command.

Crontab Types

System Crontabs (/etc/crontab, /etc/cron.d/):

  • Require root privileges
  • Can specify username
  • System-wide tasks

User Crontabs (/var/spool/cron/):

  • Per-user scheduling
  • Managed via crontab command
  • No username field needed

Access Control

Allow/Deny Files:

  • /etc/cron.allow: Whitelist (takes precedence)
  • /etc/cron.deny: Blacklist
  • No files: Only root can use cron

The At Command

For one-time task execution:

Prerequisites:

  1. Install at package: yum install at or apt install at
  2. Start service: systemctl start atd
  3. Enable at boot: systemctl enable atd

Access Control:

  • /etc/at.allow: Whitelist
  • /etc/at.deny: Blacklist

Systemd Timers

Modern alternative to cron with better integration:

Advantages:

  • Integrated logging (journald)
  • Dependency management
  • Sub-minute precision
  • Better error handling
  • Service integration

Best Practices

  1. Use absolute paths in all scripts and commands
  2. Set PATH in crontab: PATH=/usr/local/bin:/usr/bin:/bin
  3. Log output: * * * * * /script.sh >> /var/log/script.log 2>&1
  4. Email results: Set MAILTO=admin@example.com in crontab
  5. Test first: Run manually before scheduling
  6. Handle errors: Include error checking in scripts
  7. Use locking: Prevent overlapping executions with flock
  8. Monitor: Check logs regularly

Troubleshooting

Cron Not Running

1
2
3
4
5
6
7
8
9
# Check service
systemctl status cron

# View logs
tail -f /var/log/cron
grep CRON /var/log/syslog

# Test with logging
* * * * * /usr/bin/date >> /tmp/crontest.log 2>&1

Environment Issues

1
2
3
4
5
6
7
8
# Add to crontab
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
HOME=/home/user

# Or in script
#!/bin/bash
export PATH=/usr/local/bin:/usr/bin:/bin

Systemd Timer Issues

1
2
3
4
5
6
7
8
9
# Check timer status
systemctl list-timers --all
systemctl status mytimer.timer

# View service logs
journalctl -u myservice.service -n 50

# Test service manually
systemctl start myservice.service

Quick Reference Card

Most Common Patterns

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Every 5 minutes
*/5 * * * * /path/to/script.sh

# Daily at 2 AM (backups)
0 2 * * * /usr/local/bin/backup.sh

# Weekdays at 9 AM (reports)
0 9 * * 1-5 /usr/local/bin/report.sh

# First of month (billing)
0 0 1 * * /usr/local/bin/billing.sh

# Every 15 seconds (use systemd)
# See "Sub-Minute Tasks" section above

File Locations

1
2
3
4
5
/etc/crontab                    # System crontab
/etc/cron.d/                    # System cron directory
/var/spool/cron/                # User crontabs
/etc/systemd/system/            # Systemd units
/var/spool/at/                  # At jobs

Conclusion

For tasks requiring execution intervals:

  • 1 minute or more: Use cron
  • Sub-minute (like 15 seconds): Use systemd timers
  • One-time execution: Use at command
  • Complex dependencies: Use systemd timers

Choose the right tool based on your requirements for precision, complexity, and integration needs.

This post is licensed under CC BY 4.0 by the author.