Skip to content

Scheduling Tasks — crontab


Not everything needs to run continuously as a service, or only in response to something happening — plenty of real tasks need to run on a fixed schedule instead: a nightly backup, a weekly report, a cleanup script that runs every hour. cron is the traditional Linux tool for exactly that, and despite its age, it remains genuinely standard practice.

The crontab Syntax

A scheduled job is defined by a line with six fields — five specifying the schedule, followed by the command itself:

minute  hour  day-of-month  month  day-of-week  command
FieldRange
Minute0–59
Hour0–23
Day of month1–31
Month1–12
Day of week0–7 (both 0 and 7 mean Sunday)

A few special characters make these fields expressive rather than requiring one line per exact time:

SymbolMeaningExample
*Every value* in the hour field means every hour
,A list of specific values1,15 means the 1st and 15th
-A range1-5 means Monday through Friday in the day-of-week field
/A step*/15 in the minute field means every 15 minutes

Common Schedules, Read In Plain English

ScheduleMeaning
* * * * *Every minute
0 * * * *Every hour, on the hour
0 2 * * *Every day at 2:00 AM
0 2 * * 1Every Monday at 2:00 AM
*/15 * * * *Every 15 minutes
0 0 1 * *Midnight on the first day of every month

Reading any cron schedule left to right — minute, then hour, then day-of-month, then month, then day-of-week — becomes fairly natural once you’ve seen a handful of real examples.

Editing Your Own Schedule: crontab -e

crontab -e

This opens your personal crontab in your configured editor (nano, per the convention used throughout this course). Add a line:

0 2 * * * /home/you/scripts/backup.sh

Save and exit, and cron picks up the new schedule automatically — no restart or reload step needed, unlike systemd unit files.

crontab -l

Lists your current crontab without opening an editor — useful for a quick check.

crontab -r

Removes your entire crontab. There’s no per-line removal command — to delete just one job, use crontab -e and delete that specific line, saving the rest intact.

Each user’s crontab is stored separately under /var/spool/cron/crontabs/, though you should always manage it through crontab -e rather than editing that location directly.

System-Wide Scheduling

Beyond individual users’ own crontabs, /etc/crontab and files under /etc/cron.d/ serve the same purpose system-wide — with one syntax difference worth noting: these files include an extra username field between the schedule and the command, since there’s no single implicit “owner” the way a personal crontab has:

0 2 * * *  root  /usr/local/bin/system-backup.sh

For the common case of “just run this script daily/hourly/weekly,” there’s an even simpler option: drop an executable script directly into /etc/cron.daily/, /etc/cron.hourly/, /etc/cron.weekly/, or /etc/cron.monthly/, with no schedule syntax needed at all — cron runs everything in these directories on the corresponding built-in schedule automatically, using a helper called run-parts.

The Gotcha: cron’s Minimal Environment

This trips up nearly everyone the first time: a script that works perfectly when you run it yourself can fail silently when cron runs it, because cron jobs execute with a genuinely minimal environment — no interactive shell configuration loaded, and critically, a much shorter PATH than your normal login session has.

A script calling a command by name alone — python3 myscript.py, relying on python3 being found via PATH — can fail under cron even though it works fine when you type it yourself. Two reliable fixes: use absolute paths for every command inside scripts run by cron, or set PATH explicitly at the top of the crontab itself:

PATH=/usr/local/bin:/usr/bin:/bin
0 2 * * * /home/you/scripts/backup.sh

Handling Output

By default, cron emails any output a job produces (standard output and standard error both) to the crontab owner, via the local mail system — which, on a typical server with no mail setup configured, effectively goes nowhere useful. Two common approaches: redirect output explicitly to a log file, or discard it deliberately if it’s genuinely not needed, using the redirection syntax from earlier in this course:

0 2 * * * /home/you/scripts/backup.sh >> /var/log/backup.log 2>&1

This appends both standard output and error into a persistent log file — generally the better default over silently discarding everything with /dev/null, since a failing scheduled job with no output anywhere is far harder to diagnose than one with a log trail to check.

Where cron Logs

cron activity itself — not the output of the jobs it runs, but the fact that it ran them — is logged through syslog, using the cron facility from the last chapter’s facility table:

grep CRON /var/log/syslog

This confirms a scheduled job actually fired at the time you expected, independent of whatever that job’s own script logged on its own.

systemd Timers: The Modern Alternative

systemd offers its own scheduling mechanism — .timer units, briefly mentioned as a unit type back in the Units & Targets chapter — pairing a timer with a corresponding .service unit it triggers. Full timer authoring is genuinely deeper territory than this course covers, but the tradeoff is worth knowing at a glance:

Scopecronsystemd timers
UbiquityAvailable on essentially every Unix-like systemsystemd-specific
SimplicityOne-line schedule, very fast to writeRequires a separate .timer and .service unit pair
Missed-run handlingNo built-in catch-up if the system was offCan catch up missed runs on next boot (Persistent=true)
Integration with other unitsNoneCan depend on and be ordered against other systemd units

For straightforward, simple scheduling needs, cron remains the faster and more universally recognizable choice — which is exactly why it’s the one covered hands-on in this chapter.

What’s Next

With scheduled automation covered alongside continuous services, this section has now walked through nearly everything a running system does on its own. The final chapter pulls it together with real-world debugging — working through actual failure scenarios using the tools from across this entire section.

Last updated on