How to Schedule Bash Scripts with cron

Clock-driven workflow automatically backs up files and removes older log files

What You’ll Learn

In this lesson, you’ll learn how to use cron to run Bash scripts automatically on a repeating schedule. You will create a script that backs up application logs and removes log files that are no longer needed.

  • Understand what cron and a crontab are.
  • Read and write a cron schedule.
  • Run a Bash maintenance script automatically.
  • Handle important cron details such as absolute paths and output logging.

The Concept

cron is a Linux service that runs commands at scheduled times. A scheduled command is often called a cron job.

Each user can store scheduled commands in a file called a crontab. You edit your personal crontab with this command:

crontab -e

A cron schedule has five time fields followed by the command to run:

  • Minute: 0-59
  • Hour: 0-23
  • Day of the month: 1-31
  • Month: 1-12
  • Day of the week: 0-7, where Sunday is usually 0 or 7

For example, this schedule runs a command every day at 2:00 AM:

0 2 * * * /home/alex/bin/log-maintenance.sh

The asterisks mean “every possible value” for those fields. Therefore, the line means minute 0, hour 2, every day of the month, every month, and every day of the week.

Cron is useful for repetitive tasks such as cleaning old logs, creating backups, checking files, and generating reports. The computer must be running for the scheduled job to run.

Basic Example

Suppose an application stores logs in /home/alex/app/logs. The following script creates a compressed backup every time it runs, then deletes log files older than seven days. It also removes backup archives older than 30 days.

Save the script as /home/alex/bin/log-maintenance.sh:

#!/usr/bin/env bash

set -e

LOG_DIR="/home/alex/app/logs"
BACKUP_DIR="/home/alex/app/backups"
TODAY=$(date +%F)
ARCHIVE="$BACKUP_DIR/logs-$TODAY.tar.gz"

mkdir -p "$BACKUP_DIR"

tar -czf "$ARCHIVE" -C "$LOG_DIR" .

printf 'Backup created: %s\n' "$ARCHIVE"

find "$LOG_DIR" -type f -name '*.log' -mtime +7 -print -delete
find "$BACKUP_DIR" -type f -name 'logs-*.tar.gz' -mtime +30 -print -delete

printf 'Cleanup complete.\n'

Make the script executable:

chmod u+x /home/alex/bin/log-maintenance.sh

Test it manually before scheduling it:

/home/alex/bin/log-maintenance.sh

Expected Output

The exact date and the list of deleted files will depend on your system. A representative run might look like this:

Backup created: /home/alex/app/backups/logs-2026-08-18.tar.gz
/home/alex/app/logs/application-2026-08-01.log
/home/alex/app/backups/logs-2026-07-10.tar.gz
Cleanup complete.

After testing, open your crontab:

crontab -e

Add this line to run the script every day at 2:00 AM:

0 2 * * * /home/alex/bin/log-maintenance.sh >> /home/alex/app/backups/maintenance.log 2>&1

The two redirections save normal output and error output in maintenance.log. This gives you a file to inspect if the scheduled job does not behave as expected.

How the Code Works

A top-to-bottom process showing cron reading a daily schedule, launching an executable Bash maintenance script, creating a compressed log backup, deleting old logs and backup archives, and recording output and errors.
Cron reads the crontab schedule and runs the executable Bash maintenance script, which backs up logs, removes stale files, and records its output for troubleshooting.

Choosing the Bash interpreter

The first line is called a shebang:

#!/usr/bin/env bash

It tells the operating system to use Bash to run the script.

Defining locations

The variables store the log directory, backup directory, current date, and archive filename:

LOG_DIR="/home/alex/app/logs"
BACKUP_DIR="/home/alex/app/backups"
TODAY=$(date +%F)
ARCHIVE="$BACKUP_DIR/logs-$TODAY.tar.gz"

$(date +%F) runs the date command and produces a date such as 2026-08-18. Quoting the variables protects paths if they contain spaces.

Creating the backup

mkdir -p creates the backup directory if it does not already exist. The tar command creates a compressed archive:

mkdir -p "$BACKUP_DIR"
tar -czf "$ARCHIVE" -C "$LOG_DIR" .
  • -c creates an archive.
  • -z compresses it with gzip.
  • -f specifies the archive filename.
  • -C "$LOG_DIR" . tells tar to archive the contents of the log directory.

Removing old files

The find commands locate files that match specific conditions:

find "$LOG_DIR" -type f -name '*.log' -mtime +7 -print -delete

This searches for regular files, limits the results to names ending in .log, and selects files modified more than seven 24-hour periods ago. -print displays each file, while -delete removes it.

The second find command applies the same idea to compressed backups, deleting archives older than 30 days.

Adding the schedule

This cron line has the structure:

0 2 * * * command-to-run

The first two fields mean 2:00 AM. The remaining three asterisks mean every day, every month, and every day of the week.

Another Example

You can schedule different maintenance tasks at different times. For example, you might clean temporary application logs each morning and create a full log backup late at night. These entries assume that the two scripts already exist and are executable:

30 1 * * * /home/alex/bin/clean-app-logs.sh >> /home/alex/app/backups/cleanup.log 2>&1
15 23 * * * /home/alex/bin/backup-app-logs.sh >> /home/alex/app/backups/backup.log 2>&1

The first job runs at 1:30 AM every day. The second runs at 11:15 PM every day. Separating the jobs can make them easier to test and troubleshoot, especially when cleanup and backup operations need different schedules.

A few useful schedule patterns are:

0 * * * * command-to-run
0 3 * * 0 command-to-run
*/15 * * * * command-to-run
  • 0 * * * * runs at the start of every hour.
  • 0 3 * * 0 runs every Sunday at 3:00 AM.
  • */15 * * * * runs every 15 minutes.

Common Mistakes

Using relative paths

Cron does not necessarily run with the same current directory or environment as your interactive terminal. Use complete paths such as /home/alex/app/logs instead of relying on paths such as ./logs.

Forgetting executable permissions

A script scheduled directly by cron needs executable permission:

chmod u+x /home/alex/bin/log-maintenance.sh

You can also explicitly invoke Bash in the cron entry, but the script still needs a valid path:

0 2 * * * /usr/bin/env bash /home/alex/bin/log-maintenance.sh

Not testing manually

Run the script from the terminal before adding it to cron. This helps you catch incorrect paths, missing permissions, and archive errors without waiting for the scheduled time.

Ignoring errors

Without output redirection, it may be difficult to discover why a job failed. Appending >> sends normal output to a log file, while 2>&1 sends error output to the same place.

Editing the wrong crontab

A user’s crontab belongs to that user. Run crontab -e as the account that should own and run the job. Jobs that need system-level permissions may require a system administrator, but avoid giving cleanup scripts more permissions than they need.

Try It Yourself

Create a Bash script that prints the current date and lists the files in a backup directory. Make it executable, run it manually, and then schedule it to run every hour. Use an absolute path for the script and redirect its output to a log file.

For an hourly schedule, the five time fields should be:

0 * * * *

Challenge

Create a maintenance script for a project with these requirements:

  • Back up the contents of /home/alex/project/logs.
  • Store the archive in /home/alex/project/backups.
  • Use the current date in the archive name.
  • Delete .log files older than 14 days.
  • Schedule the script to run every day at 1:45 AM.
  • Write the script’s output and errors to /home/alex/project/backups/maintenance.log.

Solution

Save this script as /home/alex/bin/project-maintenance.sh:

#!/usr/bin/env bash

set -e

LOG_DIR="/home/alex/project/logs"
BACKUP_DIR="/home/alex/project/backups"
TODAY=$(date +%F)
ARCHIVE="$BACKUP_DIR/project-logs-$TODAY.tar.gz"

mkdir -p "$BACKUP_DIR"

tar -czf "$ARCHIVE" -C "$LOG_DIR" .

printf 'Backup created: %s\n' "$ARCHIVE"

find "$LOG_DIR" -type f -name '*.log' -mtime +14 -print -delete

printf 'Project log cleanup complete.\n'

Make it executable:

chmod u+x /home/alex/bin/project-maintenance.sh

Then add this line to the crontab:

45 1 * * * /home/alex/bin/project-maintenance.sh >> /home/alex/project/backups/maintenance.log 2>&1

The schedule uses minute 45 and hour 1, so cron runs the script at 1:45 AM every day. The script creates the backup before removing old log files, and the redirections preserve both normal messages and errors in the maintenance log.

Key Takeaways

  • Cron runs commands automatically according to a five-field time schedule.
  • Use crontab -e to add scheduled jobs for your user account.
  • Use absolute paths because cron may not have your normal shell environment.
  • Test a Bash script manually before scheduling it.
  • Redirect output and errors to a log file so scheduled jobs are easier to troubleshoot.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top