You’ve got a backup script. It works when you run it by hand. Now you need it to run at 2 AM every night without you babysitting the terminal. That’s where cron comes in, and getting the crontab syntax right is the difference between a script that fires on schedule and one that silently does nothing while you sleep.
This guide covers everything you need: crontab format and field values, the special characters that make scheduling flexible, the handful of crontab commands you’ll actually use, and real examples you can copy and modify. No filler, no fluff.
What Is Crontab and a Cron Job
Three terms get thrown around interchangeably, and they shouldn’t be.
Cron daemon (crond) is the background process that wakes up every minute, checks for scheduled work, and runs whatever’s due. It’s been doing this on Unix systems since the 1970s. You don’t interact with it directly.
Cron job is any single task you’ve scheduled through cron. A database backup at midnight, a log rotation on Sundays, a health-check ping every five minutes. Each one is a cron job.
Crontab (short for “cron table”) is the file where those jobs live. One line per job. Each line tells the cron daemon exactly when to run a command and what command to run.
What Is Crontab Syntax
Crontab syntax is the structured format you use to define when a cron job should fire. Every line in your crontab file follows the same pattern: five time/date fields, then the command. The cron daemon reads these lines, parses the fields, and matches them against the current system time once per minute. Get the syntax wrong and nothing happens. No error, no warning. Just silence.
Crontab Format and Field Values
Every crontab entry uses five fields before the command. They always appear in this order:
| Field | Allowed Values |
| Minute | 0-59 |
| Hour | 0-23 |
| Day of month | 1-31 |
| Month | 1-12 |
| Day of week | 0-6 (0 = Sunday; on some systems, 7 also means Sunday) |
| Command | The shell command to execute |
All five fields are mandatory. If you don’t care about a particular field, fill it with an asterisk (*). Leaving a field blank breaks the entry and cron won’t tell you about it.
Crontab Special Characters Explained
Raw numbers get you only so far. These special characters make cron expressions flexible enough to handle real scheduling needs:
| Symbol | What It Does | Example |
* (asterisk) | Matches every possible value for that field | * in the hour field = run every hour |
, (comma) | Separates a list of specific values | 1,3,5 in day-of-week = Mon, Wed, Fri |
- (hyphen) | Defines a range of consecutive values | 9-17 in the hour field = 9 AM through 5 PM |
/ (slash) | Sets a step/interval value | */10 in minute field = every 10 minutes |
L | Last day of month or last specific weekday | 1L in day-of-week = last Monday of the month |
W | Nearest weekday to the given day | 15W in day-of-month = nearest weekday to the 15th |
# (hash) | Nth occurrence of a weekday in the month | 2#3 = third Tuesday of the month |
? (question mark) | No specific value; used in day fields | ? in day-of-month = any day |
Quick note: L, W, #, and ? aren’t supported by every cron implementation. Standard Linux crontab (Vixie cron) doesn’t recognize them. You’ll find them in Quartz-based schedulers and some extended cron variants. Stick with *, commas, hyphens, and slashes if you want portable syntax.
Essential Crontab Commands
You only need four crontab commands. That’s it. Here they are:
crontab -eopens your crontab file for editing. If you don’t have one yet, it creates a fresh file. First time around, it’ll ask which text editor you prefer.crontab -llists all your current crontab entries. Use it to verify what’s actually scheduled, because guessing is how things break at 3 AM.crontab -rdeletes your entire crontab file. Not a single entry. The whole file. Gone. No confirmation prompt.crontab -ridoes the same as -r but asks you first. Use this one. Always.
That covers 99% of what you’ll do. Edit, list, and occasionally delete.
How to Use Crontab With Examples
Theory’s done. Let’s build actual crontab entries. Open your crontab file:
crontab -eYour system will ask you to pick an editor if this is your first time. Pick nano if you want the least friction. You’ll land in a text file where each new line becomes a new cron job.
One thing to remember: crontab uses your system’s current timezone. If your server’s set to UTC and you’re scheduling for “9 AM,” that’s 9 AM UTC, not your local time. Check with timedatectl if you’re unsure.
Schedule a Cron Job at a Specific Time
Say you want to run a shell script on June 10th at 8:30 AM. Here’s the entry:
30 08 10 06 * /home/user/superbackup.shMinute 30, hour 08, day 10, month 06, any day of week. Straightforward. The asterisk in the day-of-week field means “don’t care what day it falls on.”
View Crontab Entries With crontab -l
Want to see what’s already scheduled? Run:
crontab -lThis dumps every line in your crontab file to the terminal. If the output is empty, you have no cron jobs. Simple.
Edit Crontab Entries
Need to change a schedule or fix a path? Same command you used to create it:
crontab -eFind the line, edit it, save, exit. The cron daemon picks up changes automatically. No restart needed.
Run a Cron Job Every Minute
Five asterisks, then your command. That’s the every-minute pattern:
* * * * * /home/user/systemhealthcheck.shThis fires once per minute, every minute, every hour, every day. Use it for monitoring scripts or rapid polling. Don’t use it for anything heavy, or your server will hate you.
Schedule a Daily Cron Job
The @daily shortcut runs a command once per day at midnight (00:00):
@daily /home/user/systemcleanup.shIt’s cleaner than writing 0 0 * * * and means the same thing. There’s also @weekly (Sunday at midnight), @hourly (minute 0 of every hour), and @annually (January 1st at midnight).
Schedule a Cron Job for a Time Range
Need a script to run during business hours only? Use a hyphen in the hour field:
00 08-17 * * * /home/user/sync.shThis runs at the top of every hour from 8 AM through 5 PM, every day. Want weekends only? Add a day-of-week range:
00 08-17 * * 6-0 /home/user/sync.shNow it fires only on Saturday (6) through Sunday (0).
Monthly and Yearly Cron Schedules
The @monthly shortcut runs a job at midnight on the 1st of every month:
@monthly /home/user/monthlyreport.shEquivalent to 0 0 1 * *. And @yearly (or @annually) fires on January 1st at midnight. Good for certificate renewals, annual log archives, or anything you need exactly once a year.
Run a Cron Job Multiple Times a Day
Comma-separated values let you hit multiple specific times. Five times a day at noon, 3 PM, 5 PM, 7 PM, and 9 PM:
0 12,15,17,19,21 * * * /home/user/report.shEach value in the hour field is a separate trigger. The minute field is 0, so it runs at the top of each of those hours.
Run a Command After System Reboot
The @reboot directive runs a command once, right after the system starts up:
@reboot /home/user/startservices.shPerfect for launching background daemons, re-establishing SSH tunnels, or starting monitoring agents that don’t have systemd service files. It only fires on boot, not on cron daemon restarts.
Crontab File Location on Linux
Where the actual crontab files sit on disk depends on your OS:
- Debian/Ubuntu –
/var/spool/cron/crontabs/ - Red Hat/CentOS/Fedora –
/var/spool/cron/ - macOS –
/var/at/tabs/
You can peek at these directly, but editing them by hand bypasses cron’s syntax checking. Stick with crontab -e.
Additional Crontab Configuration
The basics handle most use cases. But when your cron jobs start multiplying, you’ll want logging, email control, and proper environment setup.
Create a Crontab Log File
By default, cron job output vanishes unless you capture it. Redirect stdout and stderr to a log file:
* * * * * /home/user/script.sh >> /var/log/cronjob.log 2>&1The >> appends instead of overwriting, so you keep a running history. The 2>&1 sends error messages to the same file as standard output. Without this, your script can fail silently for weeks and you’ll never know until something downstream breaks.
Disable Crontab Email Notifications
Cron sends an email to the user for every job that produces output. On a busy system, that’s a lot of local mail nobody reads. Suppress it by appending:
>/dev/null 2>&1Add this to the end of any cron job line. It sends both stdout and stderr to /dev/null. Just make sure you actually have logging set up separately, or you’ll be flying blind.
Crontab Environment Variables
Cron doesn’t load your shell profile. That means your PATH, SHELL, and other environment variables are minimal by default. Define them at the top of your crontab file:
- PATH – tells cron where to find executables. Default is usually just
/usr/bin:/bin, which is why/usr/local/binscripts fail unexpectedly. - SHELL – sets which shell cron uses. Defaults to
/bin/sh, not bash. If your scripts use bash features, set this to/bin/bash. - LOGNAME – the username that owns the crontab. Pulled from
/etc/passwd. - HOME – the home directory for the crontab owner. Also from
/etc/passwd.
Set them like any shell variable at the top of your crontab, before your job entries:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin* * * * * /home/user/script.shThis is the single most common reason cron jobs work interactively but fail when scheduled. Check your PATH first. Always.