Schedule Jobs with Cron in Linux
Learn how cron works in Linux, create system and user cron jobs, write reliable schedules, and troubleshoot permissions, logging, timing, and overlapping runs.
Cron is a Linux background scheduling service. It checks configured schedules regularly, typically once per minute, and starts commands whose time fields match the current time. A command started by cron is called a cron job.
Cron is useful for recurring maintenance, cleanup, backups, reports, log-related work, and application scripts. Because cron runs commands non-interactively, a job must not depend on a terminal, aliases, a login shell, or an interactive password prompt. Use explicit paths, verify permissions, define required environment variables, and handle output deliberately.
How Cron Jobs Work
The cron daemon is a long-running background service. It reads system schedules and user crontabs, evaluates their time fields, and launches matching commands under the configured account. A crontab, short for cron table, is either a file or a managed collection of cron schedule entries.
Cron has minute-level granularity. It is appropriate for “run at 02:30” or “run every 15 minutes,” but not for second-accurate timing. For one-time work, consider at; for service-oriented schedules with dependencies and more detailed controls, systemd timers may be a better fit.
System Jobs and User Jobs
A system cron job is machine-wide automation, commonly used for maintenance and often executed as root or another service account. A user cron job belongs to one account and runs with that account's permissions, making it suitable for personal backups or application-specific tasks.
System Cron Configuration
The common system-wide crontab is /etc/crontab. Its entries contain five scheduling fields, a username, and a command. Many distributions also use directories such as /etc/cron.hourly/, /etc/cron.daily/, /etc/cron.weekly/, and /etc/cron.monthly/, where applicable. These directory conventions vary, so inspect the target system before relying on them.
sudo cat /etc/crontab
Edit package-managed files carefully. Prefer the distribution's supported mechanisms, preserve comments and file ownership, validate syntax, and avoid changing a file that a package expects to manage. The command sudo crontab -e generally edits root's user crontab; it is not the same thing as editing /etc/crontab.
Managing User Crontabs
Use the following commands for the current account:
crontab -e
crontab -l
crontab -r
crontab -eopens the current user's crontab in an editor and creates it if necessary.crontab -llists that user's scheduled jobs.crontab -rremoves the entire crontab, including every job. Treat it as a destructive command and confirm before using it.
When supported and authorized, an administrator can manage another account:
sudo crontab -u alice -e
sudo crontab -u alice -l
Always check which account owns a schedule. Editing your own crontab does not create a job for another user.
Cron Entry Structure
Fields are separated by whitespace. The command begins after the time fields and, in a system crontab, the execution-user field; the command occupies the remainder of the line.
The system form is therefore commonly described as seven parts: five time fields, user, and command. A user crontab has six parts: five time fields and command.
# /etc/crontab: time fields, user, command
0 21 * * * root /usr/bin/rm -f /home/bob/trash/*
# User crontab: time fields, command
30 2 * * * /home/alice/bin/backup.sh >> /home/alice/logs/backup.log 2>&1
Time-Field Syntax
Some cron implementations accept names such as JAN for month 1 and MON for weekday 1. Check the local implementation's documentation before depending on names. Lines beginning with # are comments, and blank lines are ignored.
Useful Schedule Examples
Daily system cleanup
0 21 * * * root /usr/bin/rm -f /home/bob/trash/*
This runs at 21:00 every day. The wildcards match every day of the month, month, and weekday. The root field is required in an /etc/crontab-style entry. Verify the absolute path and test the file selection non-destructively before enabling a deletion job.
Daily user backup
30 2 * * * /home/alice/bin/backup.sh >> /home/alice/logs/backup.log 2>&1
This runs at 02:30 under the crontab owner's account. It uses absolute paths and appends both standard output and standard error to a log.
Every 15 minutes
*/15 * * * * /usr/local/bin/check-status
Selected hours on weekdays
0 8,12,16 * * 1-5 /home/alice/bin/report.sh
The list selects three hours, and the range selects weekdays on common cron implementations.
Scheduling Semantics and Timing Pitfalls
A job runs when the current minute matches its schedule fields. If both day-of-month and day-of-week are restricted, many traditional cron implementations use an OR rule: the job runs when either field matches, while the other time fields must also match. Some implementations or replacements may differ. Check the local cron documentation and test an important schedule rather than assuming an AND rule.
- Timezone: Cron uses the host or daemon timezone unless the implementation and configuration specify otherwise. Check the system timezone when a job fires at an unexpected local time. Network Time Protocol can help keep system clocks accurate; see NTP on Linux.
- Daylight saving time: A local hour may occur twice or not occur at all. Jobs can therefore run twice or be skipped around a clock change, depending on the cron implementation.
- Downtime: A conventional cron daemon does not generally replay every missed run after the machine is powered off. Consider anacron or another scheduler for periodic work on systems that are not always running.
- Overlap: If a job lasts longer than its interval, another instance may start before the first finishes.
Writing Reliable Cron Commands
- Use absolute paths for executables, scripts, input files, output files, and directories. The command showing the full path of a shell command can help identify executable locations.
- Cron supplies a limited environment and often a reduced
PATH. Set it explicitly when needed:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- Set application variables explicitly, or call a script that establishes its own environment. Do not rely on shell profiles, aliases, interactive authentication, or a particular working directory.
- Quote shell-special characters correctly. In many cron implementations, an unescaped percent sign (
%) separates command text from standard input; escape it as\%when a literal percent is required. - Redirect output instead of letting it disappear:
/home/alice/bin/task.sh >> /home/alice/logs/task.log 2>&1
/home/alice/bin/quiet-task.sh >/dev/null 2>&1
- Put nontrivial pipelines and error handling in an executable script. Scripts are easier to test, review, version, and log than long crontab lines.
- Check ownership and permissions on the script, its inputs, working directories, and log destinations. The executing account must be able to access each one.
- Use a predictable working directory inside the script if relative paths are unavoidable.
Preventing Overlapping Runs
Use a lock when a job must not run concurrently. The following example uses flock with nonblocking mode, so a new invocation exits if another instance already holds the lock:
*/5 * * * * /usr/bin/flock -n /tmp/import.lock /home/alice/bin/import-data.sh >> /home/alice/logs/import.log 2>&1
Measure the job's runtime and review its logs. If it regularly exceeds the interval, increase the interval or redesign the work instead of allowing uncontrolled concurrency.
Monitoring and Troubleshooting
Log locations differ by distribution and logging service. On systemd systems, inspect the service and journal:
systemctl status cron || systemctl status crond
journalctl -u cron || journalctl -u crond
Traditional logging may place cron messages in one or more of these files:
sudo grep -i cron /var/log/syslog /var/log/cron /var/log/messages 2>/dev/null
Test a schedule directly
Install a temporary job that writes a timestamp every minute:
* * * * * /usr/bin/date >> /tmp/cron-test.log 2>&1
After waiting at least one or two minutes, inspect /tmp/cron-test.log, then remove the test entry. A harmless timestamp test confirms that the intended crontab is being read and the daemon is triggering jobs.
When the command works interactively but not in cron
- Check the service status and the correct user's crontab.
- Replace relative paths and bare command names with absolute paths.
- Define required
PATHand application environment variables. - Run the command manually as the same account, not as a different administrator.
- Capture both output streams in a known writable log file.
- Check the script, input, output, and directory permissions.
Cron may email a job's output to its owner when local mail delivery is configured. MAILTO can select a recipient:
MAILTO=admin@example.com
If mail delivery is not configured or no mail reader is available, do not rely on email as your only diagnostic method; use explicit logs.
Security and Operational Safety
- Root-owned jobs have system-wide power. Minimize privileged commands and run a task as a less-privileged service account whenever possible.
- Review destructive commands, wildcard expansion, variables, and paths. First replace deletion with a listing command or use a dry-run option where available.
- Use explicit ownership and permissions for scripts and output directories. Do not allow an untrusted user to modify a script executed by root.
- Add logging and useful error handling. For backups and cleanup, consider verification, retention rules, and a recovery plan.
- Use locks such as
flockto prevent simultaneous instances. - Some systems support
/etc/cron.allowand/etc/cron.denyto control which users may use crontab. Their precedence and availability depend on the installed cron implementation.
Complete Workflow
- Write and test the script manually as the intended account.
- Use absolute paths, explicit environment settings, permissions checks, logging, and locking where appropriate.
- Choose a user crontab for personal or application work, or a system configuration for machine-wide work.
- Translate the desired time into five fields and remember that system entries add the execution user.
- Edit with
crontab -eor the authorized system mechanism rather than casually overwriting managed files. - List the crontab and inspect service and cron logs.
- Use a temporary timestamp test if the result is uncertain, then remove that test.