crontab — Schedule Recurring Commands with the cron Daemon

Practical guide to crontab — schedule recurring jobs with cron, master the five-field syntax, logging and environment, and avoid the crontab -r trap.

crontab is the classic job scheduler on Unix and Linux: you store commands alongside five time fields, and the cron daemon runs them reliably in the background – from a nightly backup to a health check every five minutes. The tricky part is rarely the schedule, it's the environment: cron starts jobs with a minimal PATH and without your login profile, a literal % in a command must be escaped, and crontab -r wipes your entire crontab with no confirmation – dangerously close to crontab -e. This guide walks you through the commands, the syntax and the pitfalls.

Managing Crontabs

crontab -e — Edit the current user's crontab file in the default editor.

crontab -e

crontab -l — List (display) the current user's crontab entries.

crontab -l

crontab -r — Remove (delete) the current user's entire crontab. Warning: no confirmation and easily confused with crontab -e – back it up first with crontab -l > backup.txt.

crontab -r

crontab -u <user> -e — Edit another user's crontab (requires root).

sudo crontab -u www-data -e

crontab -u <user> -l — List another user's crontab entries.

sudo crontab -u deploy -l

crontab <file> — Install a crontab from a file (replaces existing crontab).

crontab mycron.txt

crontab -l > <file> — Backup the current crontab to a file.

crontab -l > crontab-backup.txt

Cron Expression Format

* * * * * <command> — Format: minute (0-59) hour (0-23) day-of-month (1-31) month (1-12) day-of-week (0-7, 0 and 7 = Sunday).

30 2 * * * /usr/local/bin/backup.sh

*/n — Step value: run every n intervals.

*/5 * * * * (every 5 minutes)

n,n,n — List: run at specific values.

0 8,12,18 * * * (at 8:00, 12:00, 18:00)

n-n — Range: run for all values in the range.

0 9-17 * * 1-5 (every hour 9-17, Mon-Fri)

n-n/s — Range with step: run every s-th value within the range.

0-30/10 * * * * (at 0, 10, 20, 30 past)

Special Strings

@reboot <command> — Run once at system startup.

@reboot /home/user/start-service.sh

@yearly <command> — Run once a year (equivalent to 0 0 1 1 *).

@yearly /usr/local/bin/annual-report.sh

@monthly <command> — Run once a month (equivalent to 0 0 1 * *).

@monthly /usr/local/bin/monthly-cleanup.sh

@weekly <command> — Run once a week (equivalent to 0 0 * * 0).

@weekly /usr/local/bin/weekly-backup.sh

@daily <command> — Run once a day (equivalent to 0 0 * * *).

@daily /usr/local/bin/logrotate.sh

@hourly <command> — Run once an hour (equivalent to 0 * * * *).

@hourly /usr/local/bin/check-health.sh

Common Schedules

* * * * * — Every minute.

* * * * * /usr/local/bin/monitor.sh

*/5 * * * * — Every 5 minutes.

*/5 * * * * /usr/local/bin/check-queue.sh

*/15 * * * * — Every 15 minutes.

*/15 * * * * /usr/local/bin/sync-data.sh

0 * * * * — Every hour (at minute 0).

0 * * * * /usr/local/bin/hourly-report.sh

0 0 * * * — Every day at midnight.

0 0 * * * /usr/local/bin/daily-backup.sh

0 2 * * * — Every day at 2:00 AM.

0 2 * * * /usr/local/bin/maintenance.sh

0 9-17 * * 1-5 — Every hour during business hours (Mon-Fri, 9-17).

0 9-17 * * 1-5 /usr/local/bin/business-check.sh

0 0 * * 0 — Every Sunday at midnight.

0 0 * * 0 /usr/local/bin/weekly-cleanup.sh

0 0 1 * * — First day of every month at midnight.

0 0 1 * * /usr/local/bin/monthly-report.sh

30 4 1,15 * * — At 4:30 AM on the 1st and 15th of every month.

30 4 1,15 * * /usr/local/bin/biweekly-task.sh

Output & Logging

* * * * * <command> >> /var/log/cron.log 2>&1 — Redirect both stdout and stderr to a log file (append).

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

* * * * * <command> > /dev/null 2>&1 — Suppress all output (no email, no log).

*/5 * * * * /usr/local/bin/check.sh > /dev/null 2>&1

MAILTO="user@example.com" — Set the email recipient for cron output (place at top of crontab).

MAILTO="admin@example.com"

MAILTO="" — Disable email notifications for all cron jobs.

MAILTO=""

* * * * * <command> 2>&1 | logger -t mycron — Send output to syslog with a custom tag.

0 * * * * /usr/local/bin/task.sh 2>&1 | logger -t hourly-task

Environment Variables

PATH=/usr/local/bin:/usr/bin:/bin — Set the PATH for cron jobs (cron uses a minimal PATH by default).

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

SHELL=/bin/bash — Set the shell used to run cron commands (default is /bin/sh).

SHELL=/bin/bash

HOME=/home/user — Set the home directory for cron jobs.

HOME=/home/deploy

* * * * * . /home/user/.profile && <command> — Source the user's profile to get the full environment before running.

0 * * * * . /home/deploy/.profile && /usr/local/bin/task.sh

* * * * * env VAR=value <command> — Set a variable inline for a specific cron job.

0 2 * * * env NODE_ENV=production /usr/local/bin/node /app/worker.js

System Cron Directories

/etc/crontab — System-wide crontab file. Has an extra user field after the time fields.

0 * * * * root /usr/local/bin/system-check.sh

/etc/cron.d/ — Directory for additional system crontab files (same format as /etc/crontab).

ls /etc/cron.d/

/etc/cron.hourly/ — Scripts in this directory are run every hour by anacron/run-parts.

cp myscript.sh /etc/cron.hourly/

/etc/cron.daily/ — Scripts run once a day.

ls /etc/cron.daily/

/etc/cron.weekly/ — Scripts run once a week.

ls /etc/cron.weekly/

/etc/cron.monthly/ — Scripts run once a month.

ls /etc/cron.monthly/

Troubleshooting

grep CRON /var/log/syslog — Check the syslog for cron execution logs.

grep CRON /var/log/syslog | tail -20

journalctl -u cron — View cron logs via systemd journal.

journalctl -u cron --since today

systemctl status cron — Check if the cron daemon is running.

systemctl status cron

run-parts --test /etc/cron.daily — Test which scripts in a cron directory would be executed.

run-parts --test /etc/cron.daily

* * * * * /usr/bin/env > /tmp/cron-env.txt — Debug cron environment by dumping all environment variables.

* * * * * /usr/bin/env > /tmp/cron-env.txt 2>&1

cat /etc/cron.allow — Check which users are allowed to use crontab (if file exists).

cat /etc/cron.allow

cat /etc/cron.deny — Check which users are denied crontab access (if file exists).

cat /etc/cron.deny

Conclusion

crontab handles recurring tasks reliably in the background – for everyday work you rarely need more than crontab -e to edit, crontab -l to inspect, and the familiar five-field syntax. The most common problems come not from the schedule but from the environment: cron starts jobs with a minimal PATH and without your login profile, so use absolute paths or set PATH explicitly. A literal % in a command is interpreted as a newline by cron and must be escaped as \%. Log your output (>> logfile 2>&1) or set MAILTO, otherwise failures pass silently. And mind crontab -r: it deletes your entire crontab with no confirmation and sits right next to crontab -e on the keyboard – back it up first with crontab -l > backup.txt.

Further Reading

  • Debian Wiki: cron – how cron is set up on Debian/Ubuntu, including the system cron directories
  • crontab.guru – interactive helper to build and decode cron expressions
  • at – schedules one-off jobs at a specific time instead of recurring
  • systemctl – manages systemd services and timers as a modern cron alternative
  • journalctl – searches the systemd journal, e.g. for cron executions