Job Scheduling
Run commands automatically with cron, at, and their modern systemd-timer replacement.
On this page7 sections
So far, every command you've run happened because you typed it. Production systems also need work that happens without anyone typing anything - a nightly backup, an hourly cleanup, a report generated every Monday morning. Linux has had a tool for exactly that since the 1970s: cron.
crontab: the classic scheduler
Every user can have their own crontab (cron table) - a small file of scheduled jobs, managed with the crontab command:
crontab -e # edit your crontab in your default editor
crontab -l # list your current scheduled jobs
crontab -r # remove your entire crontab
Each line in a crontab has six fields: five that describe when, and one that says what:
minute hour day-of-month month day-of-week command
30 2 * * * /usr/local/bin/backup.sh
A * means "every value" for that field. The line above reads: run backup.sh at 02:30, every day of the month, every month, every day of the week - in other words, every night at 2:30 AM.
Reading cron syntax
| Field | Allowed values | Example |
|---|---|---|
| minute | 0-59 | 0 = on the hour |
| hour | 0-23 | 2 = 2 AM |
| day of month | 1-31 | 1 = the 1st |
| month | 1-12 | 6 = June |
| day of week | 0-6 (0 = Sunday) | 1 = Monday |
A few more real examples:
0 * * * * /usr/local/bin/hourly-check.sh # every hour, on the hour
0 9 * * 1 /usr/local/bin/monday-report.sh # 9 AM every Monday
*/15 * * * * /usr/local/bin/poll.sh # every 15 minutes
0 0 1 * * /usr/local/bin/monthly-invoice.sh # midnight on the 1st of every month
*/15 means "every 15 units," a shorthand you'll see constantly in real crontabs.
Shortcuts
Most cron implementations also accept these special strings in place of the five fields:
@reboot run once, when the system boots
@daily same as 0 0 * * *
@hourly same as 0 * * * *
@weekly same as 0 0 * * 0
at: run something once
When you need a job to run one time, not on a recurring schedule, at is the simpler tool:
echo "/usr/local/bin/deploy.sh" | at 23:00 # run once, tonight at 11 PM
atq # list pending at jobs
The modern alternative: systemd timers
On systems that already use systemd (which you met in the previous lesson), a systemd timer unit can do everything cron does, with two real advantages: it logs to journalctl like every other service, and it can easily "catch up" a missed run after the machine was off (Persistent=true). A timer unit pairs with a matching .service unit:
# backup.timer
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
Which one you reach for is mostly a matter of what the system already uses: cron is simpler and universal across every Unix-like system; systemd timers integrate better if everything else on the box is already a systemd service.
The practice terminal simulates
crontabandatwell enough to practice the real commands below - just keep in mind nothing is actually scheduled in the background afterward, since a browser tab has no daemon sitting behind it the way a real system does.
Try it
echo '30 2 * * * /usr/local/bin/backup.sh' > mycron
crontab mycron
crontab -l
echo "/usr/local/bin/deploy.sh" | at 23:00
atq
crontab mycron installs that file as your schedule, and crontab -l reads it straight back - the same round trip you'd do on a real system.
Further reading
- "The Linux Command Line" by William Shotts (No Starch Press) - covers
cron,at, andanacron(cron's laptop-friendly cousin) together. - "How Linux Works" by Brian Ward (No Starch Press) - explains systemd timers as a direct comparison to cron, including the
Persistent=behavior above.
Challenge
Write a crontab line into a file called mycron that runs /usr/local/bin/backup.sh every day at 2:30 AM, using a single redirected echo.
Want to experiment first? Try things in the practice terminal (opens in a new tab), then enter the command that solves the task here.
Quiz
Lock in the concepts. Score at least 80% to mark the lesson complete.
Done with this one?
Skipped the challenge? You can mark the lesson complete by hand.