# Scheduling with cron and systemd Timers — Bash / Shell Scripting

Source: https://www.skillbyai.com/en/bash/s-cron

> Schedule scripts reliably and account for their minimal environment.

## Scripts that run without you

**cron** runs commands on a schedule defined by five fields: minute, hour, day of month, month and day of week, so `30 2 * * *` means 02:30 every day. Edit your table with `crontab -e`; system jobs live in `/etc/cron.d/`. The classic cron surprise is its **minimal environment**: a short `PATH`, no shell profile, a different working directory and often `sh` rather than Bash, so use absolute paths, set `PATH` at the top of the crontab or script, `cd` explicitly and send output to a log, because by default cron mails output to the user, which often goes nowhere. On systemd-based Linux, **systemd timers** are a modern alternative: a `.service` unit describes the job and a `.timer` unit schedules it, with logs in the journal (`journalctl -u backup.service`), dependency handling, `Persistent=true` to catch up on runs missed while the machine was off, and randomised delays. In containers and Kubernetes, use a **CronJob** resource instead.

## A crontab entry and the equivalent systemd timer

Absolute paths, explicit logging and a lock prevent the classic cron problems.

```bash
# crontab -e
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""
30 2 * * * /usr/bin/flock -n /run/lock/backup.lock /opt/scripts/backup.sh >> /var/log/backup.log 2>&1

# /etc/systemd/system/backup.service
# [Service]
# Type=oneshot
# ExecStart=/opt/scripts/backup.sh
#
# /etc/systemd/system/backup.timer
# [Timer]
# OnCalendar=*-*-* 02:30:00
# Persistent=true
# RandomizedDelaySec=5m
# [Install]
# WantedBy=timers.target
#
# systemctl enable --now backup.timer ; journalctl -u backup.service
```

## Test with the cron environment

A script that works in your terminal may fail under cron because of PATH or working-directory differences. Test with `env -i PATH=/usr/bin:/bin /bin/bash /opt/scripts/backup.sh` to simulate the minimal environment.

**Quiz:** Why do scripts often fail under cron even though they work in a terminal?

- [ ] cron cannot run Bash at all
- [ ] cron only allows one script per day
- [x] cron runs with a minimal environment: short PATH, no profile and a different working directory
- [ ] cron removes execute permissions

*Answer:* cron runs with a minimal environment: short PATH, no profile and a different working directory. The stripped-down environment breaks scripts that rely on interactive settings.
