Skip to Content
DocsOperationsSystem AdministrationScheduled Tasks

Scheduled Tasks

Scheduled tasks allow you to automatically run commands or scripts at specified times. Ubuntu 26.04 supports two methods: the traditional cron and the more modern systemd timers.

crontab Basics

Managing crontab

# Edit the current user's crontab crontab -e # View the current user's crontab crontab -l # Delete the current user's crontab crontab -r # Edit another user's crontab (requires root) sudo crontab -u username -e # View another user's crontab sudo crontab -u username -l

cron Time Syntax

A cron expression consists of 5 time fields:

┌──────── Minute (0-59) │ ┌────── Hour (0-23) │ │ ┌──── Day of month (1-31) │ │ │ ┌── Month (1-12) │ │ │ │ ┌ Day of week (0-7, both 0 and 7 mean Sunday) │ │ │ │ │ * * * * * command

Special Characters

CharacterDescriptionExample
*Any value* * * * * every minute
,Multiple values1,15,30 * * * * at minutes 1, 15, and 30
-Range1-5 * * * * minutes 1 through 5
/Step*/10 * * * * every 10 minutes

Common Examples

# Run every minute * * * * * /path/to/script.sh # Run every hour (on the hour) 0 * * * * /path/to/script.sh # Run daily at 3:00 AM 0 3 * * * /path/to/script.sh # Run daily at 3:30 AM 30 3 * * * /path/to/script.sh # Run every Monday at 2:00 AM 0 2 * * 1 /path/to/script.sh # Run on the 1st of every month at midnight 0 0 1 * * /path/to/script.sh # Run every 5 minutes */5 * * * * /path/to/script.sh # Run at minutes 15 and 45 of every hour 15,45 * * * * /path/to/script.sh # Run weekdays (Monday-Friday) at 9:00 AM 0 9 * * 1-5 /path/to/script.sh # Run every hour from 8 AM to 6 PM daily 0 8-18 * * * /path/to/script.sh # Run every 6 months (1st of January and July) 0 0 1 1,7 * /path/to/script.sh

Special Keywords

# Equivalent shortcuts @reboot # Run at system startup @yearly # Run yearly = 0 0 1 1 * @monthly # Run monthly = 0 0 1 * * @weekly # Run weekly = 0 0 * * 0 @daily # Run daily = 0 0 * * * @hourly # Run hourly = 0 * * * * # Usage examples @reboot /opt/myapp/start.sh @daily /usr/local/bin/daily-backup.sh

Practical cron Tips

Environment Variables

The cron execution environment differs from the user’s shell environment — variables like PATH may be incomplete:

# Set environment variables at the top of your crontab SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin MAILTO=admin@example.com # Or use full paths in commands 0 3 * * * /usr/bin/rsync -av /source/ /backup/

Logging

# Redirect output to a log file 0 3 * * * /path/to/script.sh >> /var/log/myscript.log 2>&1 # Discard all output 0 3 * * * /path/to/script.sh > /dev/null 2>&1 # Log only errors 0 3 * * * /path/to/script.sh > /dev/null 2>> /var/log/myscript-error.log

Email Notifications

# Set the email recipient in crontab MAILTO=admin@example.com # Disable email notifications MAILTO=""

Viewing cron Logs

# View via journalctl journalctl -u cron.service # Or check syslog grep CRON /var/log/syslog

System-Level cron Directories

Ubuntu provides several predefined cron directories:

# Place scripts in the appropriate directory for automatic execution ls /etc/cron.hourly/ # Hourly ls /etc/cron.daily/ # Daily ls /etc/cron.weekly/ # Weekly ls /etc/cron.monthly/ # Monthly
# Add a script and ensure it has execute permission sudo cp myscript.sh /etc/cron.daily/ sudo chmod +x /etc/cron.daily/myscript.sh

The system-level cron configuration file /etc/crontab:

cat /etc/crontab
SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # 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 ) 47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) 52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

systemd Timers

systemd timers are a modern alternative to cron, offering more precise time control and better logging support.

Viewing Existing Timers

# List all active timers systemctl list-timers --all # Example output: # NEXT LEFT LAST PASSED UNIT ACTIVATES # Tue 2026-03-24 06:00:00 CST 2h left Mon 2026-03-23 06:00:00 CST 22h ago apt-daily.timer apt-daily.service

Creating a Custom Timer

Creating a timer requires two files: a .service file and a .timer file.

Step 1: Create the service file

sudo nano /etc/systemd/system/my-backup.service
[Unit] Description=Daily Backup Job [Service] Type=oneshot ExecStart=/usr/local/bin/daily-backup.sh User=root StandardOutput=journal StandardError=journal

Step 2: Create the timer file

sudo nano /etc/systemd/system/my-backup.timer
[Unit] Description=Run Daily Backup at 3 AM [Timer] OnCalendar=*-*-* 03:00:00 Persistent=true RandomizedDelaySec=300 [Install] WantedBy=timers.target

Step 3: Enable the timer

sudo systemctl daemon-reload sudo systemctl enable --now my-backup.timer # Verify systemctl list-timers | grep my-backup # Manually trigger a test run sudo systemctl start my-backup.service # View execution logs journalctl -u my-backup.service

OnCalendar Time Expressions

# Daily at 3 AM OnCalendar=*-*-* 03:00:00 # Every Monday at 9 AM OnCalendar=Mon *-*-* 09:00:00 # 1st of every month OnCalendar=*-*-01 00:00:00 # Weekdays at 8 AM OnCalendar=Mon..Fri *-*-* 08:00:00 # Every 15 minutes OnCalendar=*:0/15 # Every hour OnCalendar=hourly # Every day OnCalendar=daily # Every week OnCalendar=weekly

Verify time expressions:

# Test an expression and see upcoming trigger times systemd-analyze calendar "Mon..Fri *-*-* 08:00:00" systemd-analyze calendar "*:0/15"

Event-Based Timers

In addition to calendar-based scheduling, you can trigger based on events:

[Timer] # Run 5 minutes after system boot OnBootSec=5min # Run 1 hour after the last execution completed OnUnitActiveSec=1h # Combined usage OnBootSec=10min OnUnitActiveSec=1h

Transient Timers (One-Time Delayed Execution)

# Run a command after 30 minutes systemd-run --on-active=30m /usr/local/bin/task.sh # Run at a specific time systemd-run --on-calendar="2026-03-25 10:00:00" /usr/local/bin/task.sh

cron vs systemd Timers Comparison

Featurecronsystemd timers
Configuration complexitySimple, one lineRequires two files
LoggingManual setup requiredIntegrated with journalctl
Dependency managementNot supportedSupports service dependencies
PrecisionMinimum unit is minutesAccurate to the second
Missed tasksNot executedPersistent=true catches up
Resource controlNot supportedSupports cgroup resource limits
Random delayNot supportedRandomizedDelaySec

Best Practices

  1. Use cron for simple scheduled tasks, systemd timers for complex ones.
  2. Always log output to make troubleshooting easier.
  3. Use full paths to avoid PATH issues.
  4. Prevent task overlap — long-running tasks should use locking:
# Use flock to prevent task overlap * * * * * /usr/bin/flock -n /tmp/myjob.lock /path/to/script.sh
  1. Test before deploying — run scripts manually first to confirm they work correctly.
Last updated on