By the end of this article, youâll have at least three automated tasks running on your system. Not theoretical knowledgeâactual working cron jobs.
Thatâs the promise, and itâs achievable because cron is deceptively simple. The syntax looks intimidating at first glance (five asterisks? what?), but once you understand the pattern, youâll wonder why you waited so long to use it.
Hereâs the reality: every sysadmin who seems effortlessly productive has a secret weapon. Itâs not superhuman typing speed or encyclopedic command knowledge. Itâs a crontab full of jobs that handle the boring stuff while they focus on problems that actually require human brains. Backups run themselves. Logs rotate automatically. Reports generate overnight. Monitoring scripts check systems every five minutes.
If youâve already got basic Linux command line skills, youâre ready for this. And if youâre building toward DevOps or advancing your sysadmin career, cron mastery isnât optionalâitâs expected.
What Cron Actually Does (And Doesnât Do)
Cron is a time-based job scheduler built into virtually every Linux and Unix-like system. It runs in the background, checking its schedule every minute, and executes commands at specified times.
Thatâs it. No magic. No complex dependencies. Just ârun this command at this time.â This simplicity is what makes cron a foundational skill for IT certifications and real-world sysadmin work.
The power comes from combining this simple mechanism with shell commands and scripts. Want to:
- Back up a database every night at 2 AM?
- Clear temporary files every Sunday?
- Send yourself a disk usage report every Monday morning?
- Restart a flaky service every hour?
- Pull updates from a Git repository every 15 minutes?
All cron jobs. All running silently in the background while you do literally anything else.
What cron doesnât do: Cron wonât monitor job success, retry failed jobs, handle complex dependencies, or manage job queues. Itâs deliberately simple. For those features, youâd look at tools like Ansible for configuration management, or dedicated job schedulers like Jenkins. But for 90% of sysadmin automation needs, cron is perfect precisely because itâs simple.
The Crontab Syntax Everyone Gets Wrong
Hereâs the cron time format:
* * * * * command_to_run
â â â â â
â â â â âââ Day of week (0-7, where 0 and 7 are Sunday)
â â â âââââ Month (1-12)
â â âââââââ Day of month (1-31)
â âââââââââ Hour (0-23)
âââââââââââ Minute (0-59)
Five fields, left to right: minute, hour, day of month, month, day of week. An asterisk means âevery.â If youâre coming from a Windows background, this is Linuxâs answer to Task Schedulerâbut more powerful and completely scriptable. And yes, understanding both platforms matters for cloud computing careers.
The most common mistake: Confusing the order. People constantly mix up which field is the hour and which is the minute. The minute comes first. Always.
Letâs decode some examples:
# Run at 2:30 AM every day
30 2 * * * /path/to/script.sh
# Run every hour on the hour
0 * * * * /path/to/script.sh
# Run at midnight on the first of every month
0 0 1 * * /path/to/script.sh
# Run every 15 minutes
*/15 * * * * /path/to/script.sh
# Run at 9 AM on weekdays only
0 9 * * 1-5 /path/to/script.sh
# Run every Sunday at 3 AM
0 3 * * 0 /path/to/script.sh
Notice the */15 syntax in the fourth example. The slash means âevery nth interval.â So */15 in the minute field means âevery 15 minutes.â
You can also use commas for specific values (0,30 means âat 0 and 30 minutesâ) and ranges with dashes (1-5 means Monday through Friday).
Special Strings for Common Schedules
Cron also accepts shorthand for common schedules:
| String | Equivalent | Meaning |
|---|---|---|
@reboot | - | Run once at system startup |
@yearly | 0 0 1 1 * | Once a year, midnight Jan 1 |
@monthly | 0 0 1 * * | Once a month, midnight 1st |
@weekly | 0 0 * * 0 | Once a week, midnight Sun |
@daily | 0 0 * * * | Once a day, midnight |
@hourly | 0 * * * * | Once an hour, on the hour |
These make crontabs more readable:
@daily /home/admin/backup.sh
@hourly /usr/local/bin/check-disk-space.sh
@reboot /home/admin/start-services.sh
Your First Real Cron Job: Disk Space Alerts
Theory is boring. Letâs build something useful.
Problem: You want to know when disk space is getting low before it causes outages.
First, create a script that checks disk usage and alerts you:
#!/bin/bash
# /home/admin/scripts/disk-alert.sh
THRESHOLD=80
EMAIL="[email protected]"
df -H | grep -vE '^Filesystem|tmpfs' | awk '{ print $5 " " $1 }' | while read output; do
usage=$(echo $output | awk '{ print $1}' | cut -d'%' -f1)
partition=$(echo $output | awk '{ print $2 }')
if [ $usage -ge $THRESHOLD ]; then
echo "Warning: Partition $partition is at ${usage}% capacity" | \
mail -s "Disk Space Alert: $(hostname)" $EMAIL
fi
done
Make it executable:
chmod +x /home/admin/scripts/disk-alert.sh
Now schedule it to run every hour. Edit your crontab:
crontab -e
Add this line:
0 * * * * /home/admin/scripts/disk-alert.sh
Done. Youâll get an email whenever any partition exceeds 80% capacity. If youâve been building a home lab, this is exactly the kind of monitoring that separates a toy environment from a properly managed one.
This simple patternâscript plus cronâhandles most automation needs. The script does the actual work; cron just triggers it on schedule.
Automated Backups That Actually Work
If youâre not automating backups, youâre gambling with data. Hereâs a real backup setup using cron.
Daily Database Backup
For MySQL/MariaDB:
#!/bin/bash
# /home/admin/scripts/backup-mysql.sh
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y-%m-%d)
MYSQL_USER="backup_user"
MYSQL_PASS="your_secure_password"
# Create backup directory if it doesn't exist
mkdir -p $BACKUP_DIR
# Dump all databases
mysqldump -u$MYSQL_USER -p$MYSQL_PASS --all-databases > $BACKUP_DIR/all-databases-$DATE.sql
# Compress the backup
gzip $BACKUP_DIR/all-databases-$DATE.sql
# Delete backups older than 7 days
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete
# Log the backup
echo "$(date): Backup completed" >> /var/log/mysql-backup.log
Schedule it for 3 AM (when load is typically lowest):
0 3 * * * /home/admin/scripts/backup-mysql.sh
Weekly Full System Backup
For complete system backups:
#!/bin/bash
# /home/admin/scripts/weekly-backup.sh
BACKUP_DEST="/backup/system"
DATE=$(date +%Y-%m-%d)
HOSTNAME=$(hostname)
# Create this week's backup directory
mkdir -p $BACKUP_DEST/$DATE
# Backup important directories
tar -czvf $BACKUP_DEST/$DATE/etc-backup.tar.gz /etc
tar -czvf $BACKUP_DEST/$DATE/home-backup.tar.gz /home
tar -czvf $BACKUP_DEST/$DATE/var-www-backup.tar.gz /var/www
# Remove backups older than 4 weeks
find $BACKUP_DEST -type d -mtime +28 -exec rm -rf {} \; 2>/dev/null
echo "$(date): Weekly backup completed for $HOSTNAME" >> /var/log/system-backup.log
Schedule for Sunday at 4 AM:
0 4 * * 0 /home/admin/scripts/weekly-backup.sh
Notice the pattern: each script handles its own logging and cleanup. Self-contained scripts are easier to debug when something goes wrong at 3 AM. This kind of proper documentation and process thinking separates professionals from amateurs.
Log Rotation and Cleanup
Logs grow forever unless you manage them. While most modern systems use logrotate, cron is perfect for custom log management.
Compress and Archive Application Logs
#!/bin/bash
# /home/admin/scripts/rotate-app-logs.sh
LOG_DIR="/var/log/myapp"
ARCHIVE_DIR="/var/log/myapp/archive"
DAYS_TO_KEEP=30
mkdir -p $ARCHIVE_DIR
# Find logs older than 1 day, compress and move them
find $LOG_DIR -maxdepth 1 -name "*.log" -mtime +1 -exec gzip {} \; -exec mv {}.gz $ARCHIVE_DIR/ \;
# Delete archived logs older than retention period
find $ARCHIVE_DIR -name "*.gz" -mtime +$DAYS_TO_KEEP -delete
# Create fresh log files with proper permissions
touch $LOG_DIR/app.log
chmod 644 $LOG_DIR/app.log
Schedule nightly:
0 1 * * * /home/admin/scripts/rotate-app-logs.sh
Clean Up Temporary Files
Systems accumulate temporary files. Clean them automatically:
#!/bin/bash
# /home/admin/scripts/cleanup-temp.sh
# Clear /tmp files older than 7 days (but not directories)
find /tmp -type f -atime +7 -delete
# Clear old session files
find /var/lib/php/sessions -type f -mtime +1 -delete 2>/dev/null
# Clear old cache files
find /var/cache/apt/archives -name "*.deb" -mtime +30 -delete 2>/dev/null
# Report what was done
echo "$(date): Temp cleanup completed" >> /var/log/cleanup.log
Run weekly:
0 2 * * 0 /home/admin/scripts/cleanup-temp.sh
The difference between a well-maintained system and one that eventually crashes from disk exhaustion is usually just a few cron jobs like these. When interviewers ask about system administration, theyâre looking for candidates who think about maintenance proactively.
Monitoring and Health Checks
Cron is perfect for regular health checks. Catch problems before users report them.
Service Status Monitor
#!/bin/bash
# /home/admin/scripts/check-services.sh
SERVICES="nginx mysql ssh"
EMAIL="[email protected]"
for service in $SERVICES; do
if ! systemctl is-active --quiet $service; then
echo "Service $service is down on $(hostname)" | \
mail -s "ALERT: $service down" $EMAIL
# Attempt restart
systemctl restart $service
if systemctl is-active --quiet $service; then
echo "Service $service was restarted successfully on $(hostname)" | \
mail -s "RECOVERED: $service" $EMAIL
fi
fi
done
Check every 5 minutes:
*/5 * * * * /home/admin/scripts/check-services.sh
SSL Certificate Expiration Check
Donât let certificates expire unexpectedly:
#!/bin/bash
# /home/admin/scripts/check-ssl.sh
DOMAINS="example.com www.example.com api.example.com"
WARN_DAYS=30
EMAIL="[email protected]"
for domain in $DOMAINS; do
expiry_date=$(echo | openssl s_client -servername $domain -connect $domain:443 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -n "$expiry_date" ]; then
expiry_epoch=$(date -d "$expiry_date" +%s)
current_epoch=$(date +%s)
days_left=$(( ($expiry_epoch - $current_epoch) / 86400 ))
if [ $days_left -lt $WARN_DAYS ]; then
echo "SSL certificate for $domain expires in $days_left days" | \
mail -s "SSL Expiry Warning: $domain" $EMAIL
fi
fi
done
Run daily:
0 6 * * * /home/admin/scripts/check-ssl.sh
If youâre preparing for cybersecurity interviews or working toward a security career, demonstrating awareness of certificate management and automated monitoring will set you apart.
Environment Variables and Common Gotchas
Hereâs where most tutorials fail: they donât mention that cron runs in a minimal environment. The $PATH and other environment variables you rely on in your normal shell arenât available.
The PATH Problem
This script works in your terminal:
mysqldump --all-databases > backup.sql
But fails in cron because mysqldump might not be in cronâs default PATH. Fix it by using absolute paths:
/usr/bin/mysqldump --all-databases > /backup/backup.sql
Find the full path of any command with which:
$ which mysqldump
/usr/bin/mysqldump
Or set PATH at the top of your crontab:
PATH=/usr/local/bin:/usr/bin:/bin
0 3 * * * mysqldump --all-databases > /backup/backup.sql
The Working Directory Problem
Cron jobs donât run in your home directory. They typically run in / or the userâs home depending on the cron daemon. Always use absolute paths or explicitly cd at the start of scripts:
#!/bin/bash
cd /var/www/myapp || exit 1
./deploy.sh
The Output Problem
By default, cron emails any output to the user who owns the crontab. This can flood your inbox with successful job notifications.
Redirect output to suppress noise:
# Suppress all output
0 * * * * /path/to/script.sh > /dev/null 2>&1
# Log output to a file instead
0 * * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
# Only capture errors
0 * * * * /path/to/script.sh > /dev/null 2>> /var/log/myjob-errors.log
The 2>&1 redirects standard error (2) to the same place as standard output (1). Understanding this is part of mastering bash scripting.
Debugging Cron Jobs When Things Go Wrong
Cron jobs fail silently more often than youâd like. Hereâs how to figure out whatâs happening.
Check if Cron is Running
systemctl status cron
# or on some systems:
systemctl status crond
View Cron Logs
# Most systems log to syslog
grep CRON /var/log/syslog
# Or on RHEL/CentOS
grep CRON /var/log/cron
Test Your Script Manually
Before trusting cron, run the exact command cron will run:
/bin/bash -c '/home/admin/scripts/backup.sh'
Simulate Cronâs Environment
Cronâs minimal environment is often the culprit. Test in a similar environment:
env -i /bin/bash --noprofile --norc -c '/home/admin/scripts/backup.sh'
Add Debugging to Your Script
Temporarily add verbose output:
#!/bin/bash
exec >> /var/log/myscript.log 2>&1
set -x # Print every command before executing
# rest of your script
The set -x option prints each command before executionâinvaluable for debugging.
Check Mail
If cron is trying to email you errors but mail isnât configured, check the local mail:
cat /var/mail/$(whoami)
System Crontabs vs User Crontabs
There are two ways to schedule cron jobs:
User crontabs (crontab -e): Jobs run as your user. Use for personal automation.
System crontab (/etc/crontab): Jobs can specify which user runs them. Has an extra field:
# /etc/crontab format
* * * * * root /path/to/script.sh
# ^^^^ user field
Cron directories (/etc/cron.d/, /etc/cron.daily/, etc.): Drop scripts into these directories for automatic scheduling:
/etc/cron.hourly/- Scripts run every hour/etc/cron.daily/- Scripts run once a day/etc/cron.weekly/- Scripts run once a week/etc/cron.monthly/- Scripts run once a month
Scripts in these directories donât need cron syntaxâthey just need to be executable. The systemâs anacron or run-parts handles the scheduling.
# Make a script run daily
sudo cp myscript.sh /etc/cron.daily/
sudo chmod +x /etc/cron.daily/myscript.sh
Security Considerations
Cron jobs run with whatever privileges their user has. Be careful. If youâre interested in cybersecurity careers, understanding how scheduled tasks can be exploited (or secured) is valuable knowledge.
Donât Store Passwords in Scripts
Bad:
mysqldump -u root -p'supersecret' --all-databases
Betterâuse a credentials file:
# Create ~/.my.cnf with restricted permissions
echo "[client]
user=root
password=supersecret" > ~/.my.cnf
chmod 600 ~/.my.cnf
# Script can now connect without inline password
mysqldump --all-databases
Restrict Script Permissions
Your cron scripts shouldnât be world-writable:
chmod 700 /home/admin/scripts/*.sh
Use Absolute Paths Everywhere
Prevents path injection attacks:
# Bad - relies on PATH
rm old-files/*
# Good - explicit paths
/bin/rm /var/backup/old-files/*
Monitor Whatâs Scheduled
Regularly audit cron jobs across all users:
# List all user crontabs
for user in $(cut -f1 -d: /etc/passwd); do
crontab -l -u $user 2>/dev/null | grep -v '^#' | grep -v '^$' && echo "User: $user"
done
Use Cron Allow/Deny Lists
Control who can use cron:
# /etc/cron.allow - only listed users can use cron
# /etc/cron.deny - listed users cannot use cron
If neither file exists, the default depends on your distributionâcheck your systemâs documentation.
Real-World Cron Configuration Example
Hereâs a complete crontab for a production web server:
# Environment setup
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=[email protected]
# System Maintenance
# Clear temp files weekly
0 2 * * 0 /home/admin/scripts/cleanup-temp.sh
# Monitoring
# Check services every 5 minutes
*/5 * * * * /home/admin/scripts/check-services.sh > /dev/null 2>&1
# Check disk space hourly
0 * * * * /home/admin/scripts/disk-alert.sh > /dev/null 2>&1
# Check SSL certificates daily
0 6 * * * /home/admin/scripts/check-ssl.sh
# Backups
# Database backup at 3 AM daily
0 3 * * * /home/admin/scripts/backup-mysql.sh
# Full system backup at 4 AM Sundays
0 4 * * 0 /home/admin/scripts/weekly-backup.sh
# Application
# Clear application cache nightly
0 1 * * * /home/admin/scripts/clear-app-cache.sh
# Rotate application logs
0 0 * * * /home/admin/scripts/rotate-app-logs.sh
# Reports
# Send weekly summary every Monday at 8 AM
0 8 * * 1 /home/admin/scripts/weekly-report.sh
This server practically runs itself. The admin gets notified only when something needs attention.
Cron Alternatives Worth Knowing
Cron is simple by design. When you need more sophisticated scheduling, these tools fill the gaps:
Systemd timers: Modern alternative to cron on systemd-based systems. Better logging, dependency management, and can trigger on events besides time.
Anacron: Handles missed jobs. If the system was off when a daily job was scheduled, anacron runs it when the system starts. Many distributions use this for /etc/cron.daily/ jobs. For learning more about these underlying Linux concepts, check out the Linux Foundationâs training resources or our complete Linux guide.
at: One-time scheduled execution. Unlike cronâs recurring schedules, at runs a command once at a specified time:
echo "/home/admin/scripts/deploy.sh" | at 10:30 PM
Jenkins: When cron jobs grow into full deployment pipelines, Jenkins or similar CI/CD tools provide proper job management, logging, and visualization. Understanding when to use which tool is part of developing in-demand technical skills.
For most sysadmin work, though, cron is the right tool. Donât reach for complex solutions when a simple one works.
Building Your Automation Library
The scripts in this article are building blocks. Combine them into a personal automation library:
/home/admin/scripts/
âââ backup/
â âââ backup-mysql.sh
â âââ backup-postgres.sh
â âââ weekly-backup.sh
âââ monitoring/
â âââ check-services.sh
â âââ check-ssl.sh
â âââ disk-alert.sh
âââ maintenance/
â âââ cleanup-temp.sh
â âââ rotate-logs.sh
âââ reports/
âââ weekly-report.sh
Every time you automate something, add it to the library. Over time, setting up a new server becomes trivialâcopy your scripts, configure your crontab, done. This is also excellent resume material when you can explain how you automated your previous workplaceâs manual processes.
This kind of systematic approach to automation is exactly what distinguishes senior sysadmins from those still doing everything manually. If youâre working toward DevOps, this mindset is essential.
Practice Makes Permanent
You can read about cron all day, but it wonât stick until you use it. Hereâs a challenge:
This week, set up three cron jobs:
- A disk space alert that emails you when any partition exceeds 80%
- An automated backup of something you care about (home directory, database, config files)
- A cleanup job that removes old files from a directory
If you want structured practice, platforms like Shell Samurai offer interactive terminal challenges that build exactly these skills. Combine this with PowerShell for Windows automation and youâll have both major OS families covered.
Start simple. Get something working. Iterate. Thatâs how sysadmins actually learnânot from reading, but from doing.
Frequently Asked Questions
How do I see what cron jobs are currently scheduled?
Run crontab -l to list your userâs cron jobs. To see system-wide cron jobs, check /etc/crontab and the files in /etc/cron.d/. For other users (requires root), use crontab -l -u username.
Why didnât my cron job run?
The most common causes are: PATH issues (cron uses a minimal PATH), permission problems (script not executable or canât access required files), or environment variable issues. Check your cron logs (grep CRON /var/log/syslog) and test your script manually with env -i /bin/bash -c '/path/to/script.sh' to simulate cronâs environment.
Whatâs the difference between * * * * * and */1 * * * *?
Nothingâboth run every minute. The */1 syntax explicitly says âevery 1 minute,â but since thatâs the minimum interval anyway, itâs identical to *. Use */5 for every 5 minutes, */15 for every 15 minutes, etc.
Can I run cron jobs more frequently than once per minute?
No, cronâs minimum resolution is one minute. For sub-minute scheduling, youâd need to use a different approachâlike a script that runs in a loop with sleep, managed by systemd, or tools like fcron or systemd timers with OnUnitActiveSec.
How do I prevent multiple instances of the same cron job from overlapping?
Use a lock file mechanism in your script:
LOCKFILE=/tmp/myjob.lock
if [ -f $LOCKFILE ]; then
exit 0
fi
trap "rm -f $LOCKFILE" EXIT
touch $LOCKFILE
# rest of script
Or use the flock command: flock -n /tmp/myjob.lock /path/to/script.sh
Take Action Now
Youâve got the knowledge. Hereâs the action plan:
- Right now: Run
crontab -eand add one simple jobâeven just0 * * * * echo "test" >> /tmp/cron-test.log - Today: Pick one repetitive task you do manually and write a script for it
- This week: Set up at least the three jobs from the practice challenge
- This month: Document your cron setup and scripts so future-you (or your replacement) can understand themâadd this to your homelab documentation for your resume
The sysadmins who get promoted, who move into DevOps, who earn the higher salariesâthey all have one thing in common: they automate relentlessly. Cron is your first step.
Stop doing tasks twice. Let cron handle the boring stuff.