linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Commands/cmd-cron-crontab

kb/commands ── Commands ── beginner

cron and crontab: scheduling tasks

cron is a daemon that reads crontab files and runs jobs on a schedule. Format: `min hour day month weekday command`. anacron handles machines that are powered off. On systemd systems, timers are often used instead.

view as markdownaka: cron, crontab, cron-jobs, crontab-format

Why cron

Run a command at N o'clock every day, every 5 minutes, or on the first of each month. Forty years a Unix standard. Simple format, the daemon is always present, nothing to write beyond a schedule line.

On modern Linux, systemd-timers is increasingly the replacement. cron is still installed on RHEL, Debian, and Alpine out of the box and continues to serve millions of servers.

crontab: where the schedule lives

Three levels:

FileWho writes ituser field
crontab -e (per-user)the user, via crontababsent
/etc/crontabrootpresent (6th field)
/etc/cron.d/*packages, rootpresent
/etc/cron.{hourly,daily,weekly,monthly}/scriptsrun-parts

Personal crontab for the current user:

bash
crontab -e        # edit
crontab -l        # list
crontab -r        # delete entire crontab (careful!)
sudo crontab -u www-data -l    # another user's crontab

System files under /etc/cron.d/ use a 6-field format: the username comes before the command:

# m  h  dom mon dow user    command
  0  3  *   *   *   root    /usr/local/bin/backup.sh

Line format

┌─── minute (0-59)
│ ┌─── hour (0-23)
│ │ ┌─── day of month (1-31)
│ │ │ ┌─── month (1-12 or JAN-DEC)
│ │ │ │ ┌─── day of week (0-7, 0 and 7 = Sunday, or MON-SUN)
│ │ │ │ │
* * * * * command

Special characters:

CharacterMeaning
*every value
,list: 1,15,30
-range: 9-17
*/Nevery N: */5 every 5
0-23/2range with step

Examples:

*/5 *    *  *  *   ./tick.sh         # every 5 minutes
0   3    *  *  *   ./backup.sh       # every day at 03:00
0   2    *  *  0   ./weekly.sh       # every Sunday at 02:00
0   0    1  *  *   ./monthly.sh      # 1st of the month at midnight
30  9-18 *  *  1-5 ./reminder.sh     # at :30 past each hour from 09:30 to 18:30, Mon-Fri

@ shortcuts

AliasEquivalent
@rebootwhen cron starts (roughly at system boot)
@yearly, @annually0 0 1 1 *
@monthly0 0 1 * *
@weekly0 0 * * 0
@daily, @midnight0 0 * * *
@hourly0 * * * *

@reboot is a quick substitute for a systemd unit when you need a one-shot command at boot. For reliability, systemd-targets is the better choice.

anacron: for machines that are powered off

cron will not run a job that was due while the machine was down. anacron catches up: at boot it checks when each job last ran and executes it now if it is overdue.

/etc/anacrontab:

# period  delay  job-id     command
1         5      cron.daily run-parts /etc/cron.daily
7         25     cron.weekly run-parts /etc/cron.weekly
  • period: how many days between runs
  • delay: random delay after startup, in minutes

On laptops where @daily jobs are missed during sleep, anacron runs them on the next boot.

The cron environment: the source of 80% of bugs

cron launches commands in a minimal environment: PATH=/usr/bin:/bin, HOME set to the user's home directory, and none of the variables from ~/.bashrc or /etc/profile. A script that works fine in the shell often fails in cron for this reason.

The fix:

cron
# Set variables at the top of the crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=ops@example.com
TZ=Europe/Berlin
0 3 * * * /home/user/backup.sh
  • PATH: the most common cause of "command not found"
  • MAILTO: cron mails stdout/stderr to this address (requires an MTA)
  • SHELL: defaults to /bin/sh; set to bash if the script uses bash-only syntax
  • TZ: cron uses the system zone; on a UTC server "0 3" means 03:00 UTC

Logs

bash
journalctl -u cron -f              # systemd systems (Debian)
journalctl -u crond -f             # RHEL
grep CRON /var/log/syslog          # older Debian
/var/log/cron                      # RHEL

cron logs the fact that it ran a job, not the stdout or stderr. To see output, use MAILTO or redirect in the job itself:

cron
0 3 * * * /home/user/backup.sh >> /var/log/backup.log 2>&1

Without 2>&1, errors go to mail rather than the log file. A cleaner approach sends everything to syslog with a tag:

cron
0 3 * * * /home/user/backup.sh 2>&1 | logger -t backup

The output then appears in journalctl -t backup with timestamps.

cron vs systemd timers

Featurecronsystemd-timers
Formatone-line schedule.timer + .service unit
Logssyslog, fact-of-run onlyfull stdout/stderr via journald
DependenciesnoneAfter/Requires
Random delayanacronRandomizedDelaySec=
PersistenceanacronPersistent=true
Missed jobs after sleepanacronOnBootSec=
Long-running processunsupervisedresource limits, cgroups

For new code on systemd systems, timers are the more complete solution.

Troubleshooting

  • command not found: PATH does not include /usr/local/bin. Set it in the crontab.
  • Script cannot find a file: cron runs in the user's $HOME. Use absolute paths, or put cd as the first line of the script.
  • Job never runs: check systemctl status cron, crontab -l (syntax), and the script permissions (chmod +x).
  • Job runs but silently fails: MAILTO is unset and stdout/stderr has no redirect. Redirect output to a file and read it.
  • Job runs twice: the same entry exists in both /etc/crontab and the personal crontab.
  • Clock change, DST: at transition moments a job may run zero or two times. Use anacron-style scheduling and make jobs idempotent.
  • % in a crontab command: % is a special character in crontab; escape it as \% or wrap the command in /bin/bash -c '...'.

§ команды

bash
crontab -e

Edit the current user's crontab in `$EDITOR`

bash
crontab -l

List the active crontab. The first thing to check when debugging.

bash
sudo crontab -u www-data -l

List another user's crontab. Requires sudo.

bash
* * * * * date >> /tmp/cron-test.log

Write a timestamp every minute. Confirms that cron is running at all.

bash
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Run every day at 03:00, sending both stdout and stderr to one log file

bash
@reboot /home/user/start-tunnel.sh

Run at boot. A quick substitute for a systemd unit.

bash
journalctl -u cron --since '1 hour ago'

cron logs via journalctl. Shows job launch attempts.

§ см. также

  • systemd-timerssystemd timers as a cron replacementA systemd timer is a `.timer` unit that runs a paired `.service` on a schedule or after an interval from an event (boot, last run). It replaces cron with logs in [[cmd-journalctl]] and dependencies.
  • cmd-systemctlsystemctl: managing systemd services`systemctl` is the main CLI for managing systemd units: services, timers, mounts, and sockets. It replaces SysV init and `service` on modern distros.
  • cmd-journalctljournalctl: systemd journal`journalctl` reads the binary journal written by systemd-journald. It is the central log for the system: kernel, systemd services, syslog, all through one interface.
  • bash-scriptingbash scripts: basics and idiomsA bash script is a text file with shebang `#!/usr/bin/env bash` and `chmod +x`. Start every script with `set -euo pipefail` and run `shellcheck` to catch errors early.
  • signalsSignals (SIGTERM, SIGKILL, SIGHUP)A signal is an asynchronous notification to a process from the kernel or another process. TERM asks it to quit, KILL kills it now, HUP reloads config.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies