To schedule a cron job on Linux you run crontab -e to open your personal crontab, add one line made of a five-field schedule followed by the command, then save. For example, 0 2 * * * /home/techearl/backup.sh runs that script every day at 02:00. That single line is the whole mechanism: cron reads it, and from then on the command fires on the timer you described.
The hard part is never the editing. It is writing the five fields correctly, and getting the command to actually run once cron, rather than your interactive shell, is the thing calling it. This guide covers both.
What cron is
Cron is the time-based job scheduler that ships with every Linux distribution. A long-running daemon (cron or crond) wakes once a minute, reads every crontab on the system, and runs any job whose schedule matches the current minute. You do not start or stop it per job. You just describe when, and the daemon does the rest, in the background, whether or not you are logged in.
Each user has their own crontab, edited with crontab -e and run as that user. The system also has crontabs in /etc/crontab and /etc/cron.d/ for jobs that need to name which user they run as. For a task that is yours, the per-user crontab is the right place.
The five fields
A cron line is five space-separated time fields, then the command to run:
┌───── minute (0 - 59)
│ ┌───── hour (0 - 23)
│ │ ┌───── day of month (1 - 31)
│ │ │ ┌───── month (1 - 12)
│ │ │ │ ┌───── day of week (0 - 6, Sunday = 0)
│ │ │ │ │
0 2 * * * /home/techearl/backup.sh
Each field accepts more than a plain number:
- a number (
2) for an exact value, *for "every",- a step
*/15for "every 15", - a range
1-5(Monday to Friday in the day-of-week field), - a list
1,15(the 1st and the 15th).
So 30 9 1,15 * * runs at 09:30 on the 1st and 15th of every month, and */10 * * * * runs every ten minutes. Build a schedule below and read the expression it produces, or paste an existing line to translate it back to English:
0 9 * * *Runs at 09:00, every day.
For a focused reference you can come back to, the crontab builder page keeps just the generator and a field cheat sheet.
Schedule your first job, step by step
-
Open your crontab:
bashcrontab -eThe first time, it asks which editor to use. Pick
nanoif you are unsure. -
Add a line. To run a script every day at 2 in the morning:
code0 2 * * * /home/techearl/backup.sh -
Save and exit. The
crontabcommand repliesinstalling new crontab. That is it, the job is live. -
Confirm it is there:
bashcrontab -l
You do not restart cron, and you do not need sudo for your own crontab. Editing it as yourself schedules the job to run as you, with your permissions.
The shorthand strings
Cron understands a handful of named schedules that are easier to read than five fields:
| String | Same as | Runs |
|---|---|---|
@yearly | 0 0 1 1 * | once a year, midnight on Jan 1 |
@monthly | 0 0 1 * * | midnight on the 1st of each month |
@weekly | 0 0 * * 0 | midnight every Sunday |
@daily | 0 0 * * * | every day at midnight |
@hourly | 0 * * * * | at the start of every hour |
@reboot | (special) | once, when the machine boots |
@reboot is the odd one out: it is not a time, it runs the command once each time the system starts, which is handy for kicking off a long-running process you do not want to manage as a full service.
The traps that make a job run at the wrong time (or not at all)
These are the failures I see again and again. Almost every "my cron job did not run" turns out to be one of them.
Day-of-month and day-of-week are OR, not AND
This one is genuinely counterintuitive. 0 9 13 * 5 does not mean "9am on Friday the 13th". When both the day-of-month and the day-of-week fields are restricted, cron runs the job when either matches. So that line runs at 09:00 on the 13th of every month and on every Friday. To target a single weekday, leave day-of-month as * and set only day-of-week: 0 9 * * 5.
Why a cron job works in the terminal but not in cron
"It works when I run it by hand, but not in cron" is almost always this: cron runs with a minimal environment. Cron does not load your .bashrc or .profile, and its PATH is short (often just /usr/bin:/bin). A command that relies on your interactive PATH, or on an environment variable you set at login, will fail silently. Use absolute paths for every binary and file, and set any variables your script needs at the top of the script itself.
A bare percent sign means newline
Inside a cron command, an unescaped % is turned into a newline (and everything after the first % becomes input on stdin). This bites date one-liners constantly: date +%Y-%m-%d has to be written date +\%Y-\%m-\%d in a crontab, or wrapped in a script so the % never reaches cron.
No output goes nowhere good
If a cron command prints anything to stdout or stderr, cron tries to email that output to the user, via the local mail system. On a machine with no mailer configured, that output is simply lost, and you have no record of what happened. Redirect it yourself:
0 2 * * * /home/techearl/backup.sh >> /var/log/backup.log 2>&1
Now both normal output and errors land in a log you can actually read.
Cron uses the system timezone
A job scheduled for 02:00 runs at 02:00 in the system's timezone, not yours. Check it with timedatectl before you trust a late-night schedule. On distributions that support it, you can set CRON_TZ=Region/City at the top of the crontab to pin a specific zone.
System crontabs and other users
crontab -e edits your crontab. Two related cases:
- To schedule a job as another user, run
sudo crontab -u www-data -e. This needs root, because you are changing what another account runs. - System-wide jobs live in
/etc/crontaband drop-in files under/etc/cron.d/. Those lines have one extra field, the username to run as, between the day-of-week and the command. That is the difference that trips people up when they copy a personal crontab line into/etc/cron.d/.
For running a one-off command as a service account rather than on a timer, see run a command as another user.
Checking that it ran
Cron logs every job it starts. Where depends on the distribution:
# systemd distributions (most modern ones)
journalctl -u cron # or -u crond on RHEL-family
# older syslog setups
grep CRON /var/log/syslogIf the log shows the job started but nothing happened, the problem is inside your command (usually PATH or a relative path). If the log shows nothing at all, the schedule never matched, recheck the five fields with the builder above.
FAQ
See also
- Crontab builder: the focused generator and field cheat sheet, with a paste-to-explain mode.
- How to run a command as another user: for jobs that need to run as a service account.
- How to give a user sudo access: when a scheduled job needs elevation.
- Linux file permissions explained: make the script your cron line points at executable.
- How to create a user on Linux: set up the service account that owns a scheduled job.
Sources
Authoritative references this article was fact-checked against.





