TechEarl

How to Schedule a Cron Job on Linux

Schedule a recurring task on Linux with cron: open your crontab, write the five-field schedule, point it at a command, and avoid the environment and day-of-week traps that make jobs run at the wrong time.

Ishan Karunaratne⏱️ 9 min readUpdated
Share thisCopied
How to schedule a cron job on Linux: edit your crontab, write the five-field cron schedule, and point it at a command to run on a recurring timer.

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:

code
 ┌───── 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 */15 for "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.

minutehourday (month)monthday (week)

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

  1. Open your crontab:

    bash
    crontab -e

    The first time, it asks which editor to use. Pick nano if you are unsure.

  2. Add a line. To run a script every day at 2 in the morning:

    code
    0 2 * * * /home/techearl/backup.sh
    
  3. Save and exit. The crontab command replies installing new crontab. That is it, the job is live.

  4. Confirm it is there:

    bash
    crontab -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:

StringSame asRuns
@yearly0 0 1 1 *once a year, midnight on Jan 1
@monthly0 0 1 * *midnight on the 1st of each month
@weekly0 0 * * 0midnight every Sunday
@daily0 0 * * *every day at midnight
@hourly0 * * * *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:

code
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/crontab and 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:

bash
# systemd distributions (most modern ones)
journalctl -u cron        # or -u crond on RHEL-family

# older syslog setups
grep CRON /var/log/syslog

If 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

Sources

Authoritative references this article was fact-checked against.

TagsLinuxcroncrontabSchedulingDevOpsSystem Administration

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

How to Disable Root Login on Linux

Disable direct root login over SSH and on the console, lock the root password, and move everyone to a normal account plus sudo, without locking yourself out.

How to List Users and Groups on Linux

List every user and group from /etc/passwd and /etc/group with getent, tell human accounts from system ones by UID, and see which groups a user belongs to.