Cron, crontab and cron jobs
Three words that get mixed up all the time:
- cron is the daemon: the background service that wakes up every minute and starts any job whose schedule matches. It is called
cronon Debian and Ubuntu andcrondon RHEL, CentOS, Fedora, Rocky and AlmaLinux. - crontab (“cron table”) is the file that lists the jobs, and also the command you use to edit it. Every user has their own crontab.
- A cron job is one line in a crontab: a schedule written as a cron expression, followed by the command to run.
# minute hour day-of-month month day-of-week command
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
That job runs every night at 2:30 AM. Build the schedule part with the cron expression generator, or paste an existing line into the cron expression translator to check it.
Crontab commands
| Command | What it does |
|---|---|
crontab -e | Opens your crontab in a text editor and installs it when you save. The first time, it starts with an empty file. |
crontab -l | Prints your crontab. Without one you get “no crontab for <user>”. |
crontab -r | Deletes your entire crontab at once, without asking. |
crontab -ri | Asks for confirmation before deleting it (-i works with -r on Linux). |
sudo crontab -u alice -l | Lists another user's crontab. -u also works with -e and -r, and needs root. |
crontab mycron.txt | Replaces your crontab with the contents of a file. |
crontab -l > crontab.bak | Saves a backup copy of your crontab. |
On most keyboards r sits next to e, and crontab -r removes every job with no undo. Back up first with crontab -l > ~/crontab.bak and restore with crontab ~/crontab.bak.
How to create a cron job with crontab -e
- Open your crontab:
The first time on Ubuntu or Debian, you're asked to choose an editor; nano is the easiest. Change it later withcrontab -eselect-editor, or for a single edit withEDITOR=nano crontab -e. - Add the job on a new line: the schedule, then the command. Use absolute paths and send the output to a log file:
*/15 * * * * /home/alice/bin/sync.sh >> /home/alice/sync.log 2>&1 - Save and exit. In nano press Ctrl+O, Enter, then Ctrl+X; in vim type
:wq. crontab checks the file and printscrontab: installing new crontab. If there is a syntax error, it says so and offers to reopen the editor; nothing is installed until the file is valid. - Check that it was saved with
crontab -l. There is nothing to restart: cron notices changed crontabs within a minute. - Confirm that it ran after the first scheduled time. See how to check cron logs below.
Crontab file format
A crontab is a plain text file with one entry per line. The cron syntax cheat sheet explains the five time fields; the rest of the file follows these rules:
- Lines starting with
#are comments, and blank lines are ignored. - Lines such as
NAME=valueset environment variables for the jobs below them:SHELL,PATH,MAILTOand, on cronie,CRON_TZ. - Special strings such as
@reboot,@dailyand@hourlycan replace the five time fields. - A
%in the command becomes a newline, and everything after the first one is passed to the command as input. Write\%for a literal percent sign, as indate +\%F. - The last line needs a trailing newline. Files edited with
crontab -eusually have one; files you install withcrontab filemay not. - Save the file with Unix line endings. Windows (CRLF) line endings break entries; convert them with
dos2unix.
A complete user crontab looks like this:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""
# Back up the database every night at 2:30
30 2 * * * /usr/local/bin/db-backup.sh >> /var/log/db-backup.log 2>&1
# Clear the cache every 15 minutes during office hours
*/15 9-17 * * 1-5 /usr/local/bin/clear-cache.sh
# Start the queue worker after every reboot
@reboot /usr/local/bin/start-worker.sh
MAILTO="" stops cron from emailing each job's output. Without it, cron mails any output to the crontab's owner when a mail server is installed, and otherwise the output is thrown away. Either way, logging to a file is the reliable option.
Where crontab files are stored
| Path | What it holds |
|---|---|
/var/spool/cron/crontabs/<user> | User crontabs on Debian and Ubuntu |
/var/spool/cron/<user> | User crontabs on RHEL, CentOS, Fedora, Rocky and AlmaLinux |
/etc/crontab | The system crontab, with an extra user column |
/etc/cron.d/ | More system crontabs, added by packages or configuration tools, in the same format |
/etc/cron.daily/, /etc/cron.hourly/, /etc/cron.weekly/, /etc/cron.monthly/ | Scripts that run-parts (or anacron) runs once an hour, day, week or month |
/etc/cron.allow, /etc/cron.deny | Which users may use the crontab command |
Change user crontabs only with crontab -e: it checks the syntax and makes sure cron reloads the file. System files are edited directly as root, and each line has a user name between the schedule and the command:
# minute hour dom month dow user command
0 3 * * * root /usr/local/sbin/rotate-backups.sh
On Debian and Ubuntu, files in /etc/cron.d/ and scripts in /etc/cron.daily/ and the other folders are skipped if their names contain a dot, so backup.sh never runs there; name it backup. Files in /etc/cron.d/ must also be owned by root and not writable by group or others, and the scripts in the other folders must be executable.
How to check that a cron job ran
# Ubuntu and Debian
grep CRON /var/log/syslog
journalctl -u cron --since today
# RHEL, CentOS, Fedora, Rocky, AlmaLinux
sudo tail -n 50 /var/log/cron
journalctl -u crond --since today
# Is the cron service running?
systemctl status cron # Debian / Ubuntu
systemctl status crond # RHEL family
A log line such as CMD (/usr/local/bin/backup.sh) only shows that cron started the command. Whether the script succeeded is in its own output, which is why every example on this page sends its output to a log file. Recent Debian releases don't install rsyslog, so /var/log/syslog may not exist; use journalctl there.
Why is my cron job not running?
Work through this list in order; the first three cover most cases.
- Command not found. Cron runs jobs with a minimal
PATH, often just/usr/bin:/bin. Use absolute paths, or setPATH=at the top of the crontab. - A different environment. Cron doesn't read
~/.bashrcor~/.profile, so your variables, aliases, nvm, pyenv and virtualenvs are missing. Call interpreters by their full path, such as/home/alice/venv/bin/python. - The script isn't executable or has no shebang line. Run
chmod +x script.shand start the script with#!/bin/bash. - An unescaped
%cut the command short. Escape it as\%. - The time zone isn't what you expect. Cron uses the server's time zone, often UTC on cloud servers. Check it with
timedatectl. - The service is stopped. Start it with
sudo systemctl enable --now cron(crondon RHEL). - Both day fields are set.
0 9 1 * 1runs on the 1st and on every Monday, because cron combines the two day fields with OR. - You aren't allowed to use cron. Check
/etc/cron.allowand/etc/cron.deny. - The file name has a dot in
/etc/cron.d/or/etc/cron.daily/on Debian or Ubuntu. - A missing final newline or Windows line endings in a crontab installed from a file.
To test a command the way cron runs it, start it with an almost empty environment:
env -i HOME="$HOME" SHELL=/bin/sh PATH=/usr/bin:/bin /bin/sh -c '/usr/local/bin/backup.sh'
If it fails here, it fails under cron too.
Crontab examples
| Crontab line | Runs |
|---|---|
*/5 * * * * /usr/local/bin/check-site.sh | Every 5 minutes. |
0 * * * * /usr/local/bin/rotate-logs.sh | At 0 minutes past the hour. |
0 2 * * * /usr/local/bin/db-backup.sh | At 2:00 AM. |
0 9 * * 1-5 /usr/local/bin/send-report.sh | At 9:00 AM, Monday through Friday. |
0 0 * * 0 find /tmp -type f -mtime +7 -delete | At 12:00 AM, only on Sunday. |
0 0 1 * * /usr/local/bin/monthly-invoice.sh | At 12:00 AM, on day 1 of the month. |
@reboot /usr/local/bin/start-worker.sh | Once, when the system (cron daemon) starts up. |
More ready-made schedules: cron expression examples.
Crontab on macOS
macOS still ships cron, and crontab -e works as it does on Linux. Apple recommends launchd instead, though, and on recent versions cron can't read protected folders such as Desktop or Documents until you give /usr/sbin/cron Full Disk Access in System Settings → Privacy & Security.
Cron or systemd timers?
Most Linux distributions also offer systemd timers (systemctl list-timers). They log every run to the journal, can catch up on runs missed while the machine was off (Persistent=true), and never start a second copy while one is still running. Cron remains the quicker choice for a one-line job, and its schedule syntax is used far beyond Linux, from Kubernetes to GitHub Actions.
Frequently asked questions
What does crontab -e do?
It opens your crontab in a text editor (the one set in VISUAL or EDITOR) and, when you save and exit, checks the syntax and installs the file. If you have no crontab yet, it starts with an empty one.
How do I list all cron jobs?
Your own: crontab -l. Another user’s: sudo crontab -l -u alice. For every user, loop over the accounts with for u in $(cut -d: -f1 /etc/passwd); do sudo crontab -l -u "$u" 2>/dev/null; done, then also check /etc/crontab, /etc/cron.d/ and the /etc/cron.* folders.
How do I delete a single cron job?
Run crontab -e, delete the line (or comment it out with #) and save. Don’t use crontab -r for this: it removes every job in the file.
Do I need to restart cron after editing the crontab?
No. Cron checks for changed crontabs every minute, so jobs added with crontab -e, or in /etc/crontab and /etc/cron.d/, are picked up automatically.
How do I change the editor that crontab -e uses?
On Ubuntu and Debian, run select-editor. Anywhere else, set the EDITOR (or VISUAL) variable, for example export EDITOR=nano in ~/.bashrc, or for one edit: EDITOR=nano crontab -e.
How do I run a cron job as root?
Edit root’s crontab with sudo crontab -e, or add a file to /etc/cron.d/ whose lines name root as the user, such as 0 3 * * * root /usr/local/sbin/cleanup.
Where is the crontab file located?
User crontabs are in /var/spool/cron/crontabs/ on Debian and Ubuntu and in /var/spool/cron/ on RHEL-based systems. The system crontab is /etc/crontab, with more files in /etc/cron.d/. Edit your own with crontab -e rather than opening the spool file.