Cron Monitoring

How to Edit Crontab Safely: Commands, Examples and Common Mistakes.

Written by noc724 team9 min readUpdated Oct 18, 2026

A scheduled job that runs perfectly from your terminal can fail the moment cron starts it. Most of those failures are introduced while the crontab is being edited: a typo in a time field, a relative path, a variable that only exists in your login shell, or simply the wrong user's file.

This guide walks through editing a crontab the safe way, explains why jobs break after an edit, and shows how to confirm that a change actually works instead of hoping it does.

Key takeaways

  • Always edit with crontab -e - it checks the file before installing it.
  • Back up the current crontab with crontab -l before every change.
  • Cron runs with a tiny environment: use absolute paths and set PATH and SHELL yourself.
  • Send each job's output to a log file, or failures disappear without a trace.
  • A crontab that installs correctly can still never run - watch the first runs, or use heartbeat monitoring.
Downtime happens. Get notified!

noc724 checks your websites, servers and APIs around the clock and alerts you by SMS, Telegram or Bale the moment something breaks.

Register for FREE

What "editing a crontab" actually means

A crontab ("cron table") is a per-user list of scheduled commands. Each line pairs a schedule with a command, and the cron daemon reads the installed tables and starts the commands on time.

There are two ways to change one:

  • crontab -e opens a temporary copy of your table in an editor. When you save and quit, the crontab tool checks the syntax and installs the new version.
  • Editing the spool files directly (for example under /var/spool/cron/) skips that check, can leave wrong ownership or permissions behind, and is the easiest way to make cron silently ignore a table.

Use crontab -e for user crontabs. System-wide jobs belong in /etc/crontab or /etc/cron.d/, which you edit as root with a normal editor - note that those files have an extra user field on every line.

There is also a difference between editing and *replacing*: crontab jobs.txt swaps the whole table for the contents of a file. That is handy for automation, and dangerous when typed by hand into the wrong account.

Choosing the editor crontab opens

crontab -e doesn't have an editor of its own. It looks at the VISUAL variable, then EDITOR, and falls back to a system default (often vi, sometimes nano). Check what you have:

echo "VISUAL=$VISUAL EDITOR=$EDITOR"

Picking an editor for one session

EDITOR=nano crontab -e

Making the choice permanent

Add the variable to your shell's start-up file (~/.bashrc for Bash, ~/.zshrc for Zsh) and open a new shell:

echo 'export EDITOR=nano' >> ~/.bashrc

Debian and Ubuntu

On Debian-based systems select-editor stores your choice in ~/.selected_editor, and crontab -e uses it from then on.

Minimal servers and containers

Slim images often ship without nano or even vi. Install one, or generate the file elsewhere and install it with crontab file - just keep a copy of the old table first.

Crontab syntax in two minutes

Every job line has five time fields followed by the command:

# ┌ minute (0-59)
# │ ┌ hour (0-23)
# │ │ ┌ day of month (1-31)
# │ │ │ ┌ month (1-12)
# │ │ │ │ ┌ day of week (0-7, 0 and 7 are Sunday)
# │ │ │ │ │
  30 2 * * * /usr/local/bin/backup.sh

Operators you will use

OperatorMeaningExample
*every value* * * * * - every minute
,a list0 9,17 * * * - 09:00 and 17:00
-a range0 9-17 * * 1-5 - hourly, office hours, weekdays
/a step*/15 * * * * - every 15 minutes

The day-of-month / day-of-week trap

When both day fields are restricted, cron runs the job when either matches, not when both do. 0 0 1 * 1 runs on the 1st of every month *and* on every Monday.

Special strings

Most cron implementations accept shortcuts such as @reboot, @hourly, @daily, @weekly and @monthly. They are easier to read, but check that your cron supports them before relying on them.

If you'd rather not count fields by hand, build the expression with the cron expression generator and paste the result.

A safe editing routine

1. Back up the current table

crontab -l > ~/crontab-backup-$(date +%F).txt

If something goes wrong, crontab ~/crontab-backup-2026-10-18.txt puts the old version back.

2. Test the command outside cron

Run it exactly as cron will: full paths, from a neutral directory, ideally with a stripped environment.

cd / && env -i HOME="$HOME" SHELL=/bin/sh PATH=/usr/bin:/bin /usr/local/bin/backup.sh

If it fails here, it will fail under cron too.

3. Edit, save and read the result

After saving, crontab prints installing new crontab. If it reports an error, it offers to re-open the editor - accept, and fix the line instead of discarding your work. Then list the table to see what is really installed:

crontab -l

4. Watch the first run

Schedule a near-term run (for example two minutes from now), confirm it happened in the log, then set the real schedule.

Common mistakes and how to fix them

"bad minute" or "errors in crontab file"

A time field holds an impossible value (60 minutes, month 13), a field is missing, or a stray character slipped in. The error names the line - fix it when crontab offers to re-edit.

The last line never runs

Many cron versions ignore a final line that doesn't end with a newline. Leave an empty line at the end of the file.

Percent signs cut the command short

In a crontab, an unescaped % ends the command and turns the rest into standard input. A date +%F inside a job must be written as date +\%F.

Editing the wrong user's table

sudo crontab -e edits root's crontab, not yours. Jobs that need your files, keys or permissions then run as the wrong user. Use crontab -u name -e when you really mean another account, and check with crontab -u name -l.

Not allowed to use crontab

If /etc/cron.allow exists, only the users listed in it may have crontabs; otherwise anyone not in /etc/cron.deny may. A "you are not allowed" message means the user is missing from one of these lists.

Why jobs stop working after an edit

Cron's environment is almost empty

Cron does not load your .bashrc or .profile. PATH is usually just /usr/bin:/bin, SHELL is /bin/sh, and variables you exported in your terminal are not there. Commands found in /usr/local/bin, a virtualenv or a version manager are simply "not found".

Relative paths

Jobs start in the user's home directory. ./run.sh or python script.py works in your terminal because you happen to be in the right folder; under cron it doesn't. Use absolute paths for the program and for every file it touches.

sh is not bash

Arrays, [[ ]], source and other Bash features fail under /bin/sh. Set SHELL=/bin/bash at the top of the crontab, or start the job with /bin/bash /path/script.sh.

Output goes nowhere

Without redirection, cron tries to mail the output to the user; on most servers no mail is set up, so errors vanish. Redirect both streams:

*/10 * * * * /opt/app/sync.sh >> /var/log/app-sync.log 2>&1

Setting environment variables in a crontab

Variable lines go above the jobs that need them and apply to every line below:

SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
APP_ENV=production

0 3 * * * /opt/app/bin/nightly-report >> /var/log/nightly-report.log 2>&1

Cron does not expand variables in these assignments - PATH=$PATH:/opt/bin stores the literal text. Write the full value. Once a job needs more than a couple of variables, move the setup into a wrapper script and keep the crontab line short.

Editing crontabs from scripts

Configuration tools and deploy scripts should never open an editor. Two safe patterns:

Replace from a version-controlled file

crontab /srv/deploy/app.crontab

The file in your repository becomes the single source of truth, and every change is reviewed like code.

Add one line without losing the others

( crontab -l 2>/dev/null | grep -v 'nightly-report' ; echo '0 3 * * * /opt/app/bin/nightly-report' ) | crontab -

The grep -v removes an older copy of the same job first, so running the script twice doesn't create duplicates.

Prevent overlapping runs

A job that sometimes takes longer than its interval can end up running twice at once. flock lets only one copy run:

*/5 * * * * flock -n /tmp/sync.lock /opt/app/sync.sh >> /var/log/app-sync.log 2>&1

Knowing that the job really runs

An installed crontab only proves the schedule was accepted. It says nothing about whether the job started, finished, or did its work. Logs help after the fact, but nobody reads them at 3 a.m.

Heartbeat monitoring closes that gap: the job calls a unique URL when it finishes, and if the call doesn't arrive on time you get an alert.

0 3 * * * /opt/app/backup.sh && curl -fsS -m 10 https://YOUR-HEARTBEAT-URL > /dev/null

The && means the ping is sent only when the backup succeeded, so a failed run and a run that never started both raise an alert. noc724's cron job monitoring works this way and sends the alert by SMS, Telegram or Bale.

Conclusion

Editing a crontab safely comes down to a short routine: back up, test the command the way cron will run it, edit with crontab -e, read back what was installed, and watch the first run. Most "it worked before I edited it" problems are environment problems - paths, shells and variables - rather than cron itself. And because cron never tells you when a job silently stops, pair every important job with a heartbeat check.

Frequently asked questions

  • Run crontab -e. It opens your user's table in the editor set by VISUAL or EDITOR and installs it when you save.

  • crontab -l lists your table; sudo crontab -u name -l lists another user's. System jobs live in /etc/crontab and /etc/cron.d/.

  • No. crontab -e notifies the daemon; it picks up the new table within a minute. Files in /etc/cron.d/ are also re-read automatically on most systems.

  • crontab -r deletes your whole table without asking. Take a backup with crontab -l first - and note how close -r is to -e on the keyboard.

  • Usually because of the environment: a short PATH, /bin/sh instead of Bash, missing variables or relative paths. Use absolute paths and set the variables in the crontab or in a wrapper script.

Share this article:XTelegramLinkedInFacebookReddit
noc724

Written by

The noc724 team

Uptime monitoring engineers

We build and run noc724, an uptime monitoring service that checks websites, servers and APIs from several cities in Iran. These guides come from the problems we and our users run into while keeping services online.

Contact the team

Expert on:Cron Monitoring

Questions?Contact Support
Feature suggestions?Share

Recent Articles