Automation is the key to efficient system administration. Cron is Linux's time-based job scheduler that allows you to run scripts and commands automatically at specified times. This comprehensive guide explains cron from the ground up, with every concept explained in detail for absolute beginners.
🎯 What You'll Learn: In this hands-on tutorial, you'll discover:
- What cron is and why it's essential for automation
- Understanding the five-field cron time syntax
- Creating and managing cron jobs with
crontab
- Special time shortcuts like
@daily
and@reboot
- Writing scripts optimized for cron execution
- Testing and debugging cron jobs
- Common pitfalls and how to avoid them
- Real-world automation examples
⏰ What is Cron?
Cron is a time-based job scheduler in Unix-like operating systems. It runs in the background (as a daemon called crond
) and executes commands or scripts at scheduled intervals.
Why Use Cron?
Without cron, you'd have to:
- Manually run backups every night
- Remember to clean up temporary files
- Stay awake to run reports at midnight
- Manually check system health every hour
With cron, you can:
- Schedule automatic backups
- Clean up files while you sleep
- Generate reports at any time
- Monitor systems 24/7
Cron handles repetitive tasks so you don't have to!
🎯 Understanding Cron Syntax
Every cron job follows a specific time format. Let's break it down completely.
The Five Time Fields
* * * * * command-to-execute
│ │ │ │ │
│ │ │ │ └─── 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)
Field Value Ranges
Field | Range | Special Values | Meaning |
---|---|---|---|
Minute | 0-59 | * = every minute | Which minute of the hour |
Hour | 0-23 | * = every hour | 24-hour format (0 = midnight) |
Day of month | 1-31 | * = every day | Which day of the month |
Month | 1-12 | * = every month | 1=Jan, 12=Dec |
Day of week | 0-7 | 0,7=Sun, 1=Mon | Which day of the week |
Special Characters in Cron
Character | Meaning | Example |
---|---|---|
* | Any value (wildcard) | * * * * * = every minute |
, | Value list separator | 0,15,30,45 = 0, 15, 30, 45 minutes |
- | Range of values | 1-5 = Monday through Friday |
/ | Step values | */5 = every 5 units |
📚 Cron Schedule Examples Explained
Let's look at real examples to understand the syntax:
Example 1: Every Minute
* * * * * /path/to/script.sh
Breaking it down:
*
(minute) = Every minute (0-59)*
(hour) = Every hour (0-23)*
(day) = Every day (1-31)*
(month) = Every month (1-12)*
(weekday) = Every day of the week (0-7)
Result: Script runs every single minute of every hour, every day.
Example 2: Every Hour at 30 Minutes Past
30 * * * * /path/to/script.sh
Breaking it down:
30
(minute) = At exactly 30 minutes past*
(hour) = Every hour*
(day) = Every day*
(month) = Every month*
(weekday) = Every weekday
Result: Runs at 00:30, 01:30, 02:30, ... 23:30 every day.
Example 3: Daily at 2:30 AM
30 2 * * * /path/to/backup.sh
Breaking it down:
30
(minute) = At 30 minutes2
(hour) = At 2 AM*
(day) = Every day of the month*
(month) = Every month*
(weekday) = Any day of the week
Result: Runs at 2:30 AM every single day.
Example 4: Every Monday at 9:00 AM
0 9 * * 1 /path/to/weekly-report.sh
Breaking it down:
0
(minute) = At 0 minutes (on the hour)9
(hour) = At 9 AM*
(day) = Any day of month*
(month) = Any month1
(weekday) = Monday (0=Sunday, 1=Monday, etc.)
Result: Runs at 9:00 AM every Monday.
Example 5: First Day of Every Month
0 0 1 * * /path/to/monthly-cleanup.sh
Breaking it down:
0
(minute) = At minute 00
(hour) = At midnight (00:00)1
(day) = On the 1st day of the month*
(month) = Every month*
(weekday) = Any weekday
Result: Runs at midnight on the 1st of every month.
Example 6: Every 15 Minutes
*/15 * * * * /path/to/monitor.sh
Breaking it down:
*/15
(minute) = Every 15 minutes (0, 15, 30, 45)*
(hour) = Every hour*
(day) = Every day*
(month) = Every month*
(weekday) = Every weekday
Result: Runs at :00, :15, :30, :45 of every hour, every day.
The /
operator: */15
means "start at 0, then step by 15". So: 0, 15, 30, 45, then repeat.
Example 7: Weekdays Only at 6 PM
0 18 * * 1-5 /path/to/workday-report.sh
Breaking it down:
0
(minute) = At minute 018
(hour) = At 6 PM (18:00 in 24-hour format)*
(day) = Any day of month*
(month) = Any month1-5
(weekday) = Monday through Friday
Result: Runs at 6:00 PM only on weekdays (Monday-Friday).
The -
operator: 1-5
specifies a range from 1 (Monday) to 5 (Friday).
Example 8: Multiple Specific Times
0,30 8,17 * * * /path/to/twice-daily.sh
Breaking it down:
0,30
(minute) = At minute 0 AND minute 308,17
(hour) = At 8 AM AND 5 PM*
(day) = Every day*
(month) = Every month*
(weekday) = Every weekday
Result: Runs at 8:00, 8:30, 17:00, and 17:30 every day.
The ,
operator: Lists multiple specific values. 0,30
means "at 0 and at 30".
🚀 Creating Your First Cron Job
Let's create a practical cron job step by step.
Step 1: Create a Test Script
First, create a simple script that writes to a file:
mkdir cron
cd cron
nano cron_test.sh
Step 2: Write the Script
#!/bin/bash
echo "Cron test" >> ~/cron_output.txt
Understanding the Script
#!/bin/bash
Purpose: Tells the system to use Bash to execute this script.
echo "Cron test" >> ~/cron_output.txt
Purpose: Appends "Cron test" to a file in the home directory.
Breaking it down:
echo "Cron test"
- Outputs the text "Cron test">>
- Append operator (doesn't overwrite)~/cron_output.txt
- File in your home directory (~
expands to home path)
💡 Why Append (>>
): Using >>
instead of >
means each cron execution adds a new line rather than replacing the file. This lets you track how many times the job ran.
Step 3: Make the Script Executable
chmod +x cron_test.sh
What this does: Adds execute permission so cron can run the script.
Step 4: Get the Full Script Path
Cron requires absolute paths (full paths from root), not relative paths.
pwd
Output:
/home/centos9/Razzaq-Labs-II/random/random/error_handling/cron
Your full script path:
/home/centos9/Razzaq-Labs-II/random/random/error_handling/cron/cron_test.sh
⚠️ Critical: Always use absolute paths in cron jobs. Relative paths don't work because cron runs in a minimal environment without your normal shell context.
Step 5: Open Crontab Editor
crontab -e
What this does: Opens your personal crontab (cron table) in the default text editor.
On first run: The system might ask you to choose an editor. Select nano
or your preferred editor.
The crontab
command:
crontab -e
- Edit your crontabcrontab -l
- List your crontab entriescrontab -r
- Remove your crontab (be careful!)
Step 6: Add the Cron Job
In the editor, add this line:
* * * * * /home/centos9/Razzaq-Labs-II/random/random/error_handling/cron/cron_test.sh
This schedule:
* * * * *
= Every minute- Followed by the absolute path to your script
Save and exit the editor.
Output after saving:
crontab: installing new crontab
What happened: Your cron job is now active and will run every minute!
Step 7: Verify the Cron Job
crontab -l
Output:
* * * * * /home/centos9/Razzaq-Labs-II/random/random/error_handling/cron/cron_test.sh
What this shows: Your currently scheduled cron jobs.
Step 8: Wait and Check Results
Wait at least 60 seconds, then check the output file:
sleep 60
cat ~/cron_output.txt
Output:
Cron test
Cron test
What happened: The script ran twice (once per minute for 2 minutes)!
Check again after a few more minutes:
cat ~/cron_output.txt
Output:
Cron test
Cron test
Cron test
Cron test
Cron test
Cron test
Perfect! Each line represents one execution.
Step 9: Understanding What Happened
Let's trace the entire flow:
- Cron daemon (
crond
) is always running in the background - Every minute, it checks all crontabs
- At second 0 of each minute, it sees your job needs to run
- Cron executes your script in a new shell process
- The script appends "Cron test" to the file
- Process completes, cron waits for the next minute
- Cycle repeats indefinitely
🛑 Stopping Your Test Cron Job
Since this job runs every minute, you'll want to stop it:
crontab -e
Delete the line or comment it out by adding #
at the start:
# * * * * * /home/centos9/Razzaq-Labs-II/random/random/error_handling/cron/cron_test.sh
Save and exit.
Verify it's removed:
crontab -l
Output: Should show no active jobs (or just commented lines).
📋 Special Time Shortcuts
Cron provides convenient shortcuts for common schedules:
Shortcut | Equivalent | Meaning |
---|---|---|
@reboot | N/A | Run once at system startup |
@yearly | 0 0 1 1 * | Once a year at midnight on Jan 1 |
@annually | 0 0 1 1 * | Same as @yearly |
@monthly | 0 0 1 * * | Once a month at midnight on the 1st |
@weekly | 0 0 * * 0 | Once a week at midnight on Sunday |
@daily | 0 0 * * * | Once a day at midnight |
@midnight | 0 0 * * * | Same as @daily |
@hourly | 0 * * * * | Once an hour at minute 0 |
Example usage:
@daily /path/to/daily-backup.sh
@reboot /path/to/startup-script.sh
@hourly /usr/local/bin/check-system-health.sh
🔧 Best Practices for Cron Scripts
1. Always Use Absolute Paths
# Wrong - relative path
cron_job.log
# Right - absolute path
/home/username/logs/cron_job.log
2. Set Environment Variables
Cron runs with a minimal environment. Set variables your script needs:
#!/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
HOME=/home/username
export PATH HOME
# Rest of your script
3. Redirect Output for Debugging
Capture both stdout and stderr:
* * * * * /path/to/script.sh >> /path/to/logfile.log 2>&1
Breaking it down:
>> /path/to/logfile.log
- Append stdout to log2>&1
- Redirect stderr (2) to wherever stdout (1) is going
4. Email Notifications
By default, cron emails output to the user. To disable:
MAILTO=""
* * * * * /path/to/script.sh
To send to specific email:
MAILTO="admin@example.com"
* * * * * /path/to/script.sh
5. Lock Files to Prevent Overlap
Prevent multiple instances of the same job:
#!/bin/bash
LOCKFILE="/tmp/myscript.lock"
if [ -e "$LOCKFILE" ]; then
echo "Script already running"
exit 1
fi
touch "$LOCKFILE"
# Your script logic here
rm "$LOCKFILE"
🐛 Debugging Cron Jobs
Check if Cron is Running
systemctl status crond
Expected output: Should show "active (running)".
Check Cron Logs
# On systems with systemd
journalctl -u crond
# On older systems
tail -f /var/log/cron
Test Your Script Manually First
Before adding to cron:
# Run the script directly
bash /full/path/to/script.sh
# Check if it works
echo $? # Should return 0 for success
Common Issues and Solutions
Problem | Cause | Solution |
---|---|---|
Script doesn't run | Not executable | Run chmod +x script.sh |
Command not found | PATH not set | Use absolute paths or set PATH |
Works manually, not in cron | Environment differs | Set all needed env variables |
No output visible | Not redirecting output | Add >> logfile 2>&1 |
Runs multiple times | Multiple crontab entries | Check with crontab -l |
🎯 Best Practices
✅ Cron Job Best Practices
- Use absolute paths: Always provide full paths to scripts and files
- Test scripts first: Run manually before adding to cron
- Log everything: Redirect output to log files for troubleshooting
- Set environment: Define PATH, HOME, and other needed variables
- Handle errors gracefully: Check return codes and implement error handling
- Prevent overlaps: Use lock files for long-running jobs
- Document your crontab: Add comments explaining each job
- Start with infrequent schedules: Test with hourly before moving to every minute
- Monitor execution: Check logs regularly to ensure jobs are running
- Use meaningful script names:
backup-database.sh
beatsscript1.sh
✅ Script Design for Cron
- Be silent on success: Only output on errors (or use log files)
- Use exit codes: Return 0 for success, non-zero for errors
- Make scripts idempotent: Safe to run multiple times
- Clean up after yourself: Remove temporary files
- Don't assume user context: Set all needed context in the script
- Handle missing dependencies: Check if required tools exist
📝 Command Cheat Sheet
Crontab Management
# Edit your crontab
crontab -e
# List your crontab
crontab -l
# Remove your crontab (careful!)
crontab -r
# Edit another user's crontab (as root)
crontab -u username -e
Common Cron Schedules
# Every minute
* * * * * /path/to/script.sh
# Every 5 minutes
*/5 * * * * /path/to/script.sh
# Every hour at minute 30
30 * * * * /path/to/script.sh
# Every day at 2:30 AM
30 2 * * * /path/to/script.sh
# Every Sunday at 3:00 AM
0 3 * * 0 /path/to/script.sh
# Every weekday at 6:00 PM
0 18 * * 1-5 /path/to/script.sh
# First day of every month at midnight
0 0 1 * * /path/to/script.sh
# Every 15 minutes during work hours (9am-5pm)
*/15 9-17 * * * /path/to/script.sh
# Twice a day (8am and 8pm)
0 8,20 * * * /path/to/script.sh
Using Special Time Shortcuts
# At system startup
@reboot /path/to/startup-script.sh
# Once a day at midnight
@daily /path/to/daily-backup.sh
# Once an hour
@hourly /path/to/hourly-check.sh
# Once a week
@weekly /path/to/weekly-report.sh
# Once a month
@monthly /path/to/monthly-cleanup.sh
Output Redirection in Cron
# Redirect output to log file
* * * * * /path/to/script.sh >> /var/log/script.log 2>&1
# Discard all output
* * * * * /path/to/script.sh > /dev/null 2>&1
# Send only errors to log
* * * * * /path/to/script.sh 2>> /var/log/script-errors.log
# Append to log with timestamps
* * * * * echo "$(date): Running script" >> /var/log/cron.log && /path/to/script.sh
🎯 Real-World Automation Examples
Example 1: Daily Database Backup
# Run every day at 2:30 AM
30 2 * * * /home/admin/scripts/backup-database.sh >> /var/log/backup.log 2>&1
Example 2: Clean Temporary Files
# Run every Sunday at 3:00 AM
0 3 * * 0 /usr/local/bin/cleanup-temp-files.sh
Example 3: Check Disk Space Every Hour
# Run every hour
@hourly /home/admin/scripts/check-disk-space.sh
Example 4: Generate Report on First of Month
# Run at midnight on the 1st of every month
0 0 1 * * /home/admin/reports/monthly-report.sh
🚀 Summary
🎓 What You've Learned
Throughout this 4-part series, you've mastered:
Part 1: Case statements and functions for organized code Part 2: Arrays and command substitution for dynamic scripts Part 3: Logging, error handling, and string manipulation Part 4: Cron jobs for automating recurring tasks
You now have the skills to write professional, maintainable, automated Bash scripts!
🎉 Congratulations! You've completed the Bash Advanced Scripting series! You can now create sophisticated automation with case statements, functions, arrays, error handling, string manipulation, and scheduled cron jobs.
What did you think of this series? Share your automation projects and cron job use cases in the comments below!
💬 Discussion
I'd love to hear about your experience:
- What tasks are you automating with cron?
- Have you encountered any tricky cron scheduling challenges?
- What automation projects are you planning?
- What other Bash topics would you like to learn?
Connect with me: