Bash script that creates a zstd-compressed tar archive of a directory and deletes backups older than 2 days.

Table of Contents#

  1. Overview
  2. Prerequisites
  3. Parameters
  4. The Script
  5. Usage
  6. How It Works
  7. Troubleshooting
  8. See Also
  9. Sources

1. Overview#

This script performs a daily directory backup by compressing the source into a single .tar.zst archive using parallel zstd (pzstd) at compression level 15. After creating the backup, it removes old backup files from the destination to prevent disk exhaustion.

The script is intended to be scheduled via cron (e.g., daily at 03:00).

2. Prerequisites#

  • pzstd - parallel zstd compression (part of the zstd package)
  • tar - GNU tar for archiving
  • find - GNU findutils for cleanup
  • Sufficient disk space at the backup destination
  • Write permission to the backup destination directory

Install on Debian/Ubuntu:

sudo apt install zstd tar

Install on Arch Linux:

sudo pacman -S zstd tar

3. Parameters#

Edit these variables at the top of the script before use:

VariableDescriptionExample
backdestDestination directory for backup archives/mnt/Backup/destination
backsourceSource directory to back up/path/to/dir

The retention period is controlled by the -mtime value in the find cleanup command (see How It Works).

4. The Script#

#!/bin/bash

# Backup variables
backdest="/mnt/Backup/destination"
backsource="/path/to/dir"

# Date label for backup filename (YYYY-MM-DD)
date=$(date "+%F")

# Create compressed archive using parallel zstd at level 15
tar -cv -I "pzstd -15" -f "$backdest/Something-$date.tar.zst" "$backsource"

# Delete backups with modification time older than 2 days
# -mtime +2 matches files modified MORE than 2*24 hours ago
find "$backdest/" -mtime +2 -delete

5. Usage#

Manual Execution#

chmod +x /opt/scripts/BackupDir.sh
/opt/scripts/BackupDir.sh

Cron Schedule#

Run daily at 03:00:

0 3 * * * /opt/scripts/BackupDir.sh >> /var/log/backup-dir.log 2>&1

Dry Run#

Test what the cleanup would delete without actually removing files:

# Preview which files would be deleted
find /mnt/Backup/destination/ -mtime +2 -print

6. How It Works#

  1. Archive creation - tar -cv -I "pzstd -15" creates a verbose tar archive and pipes it through parallel zstd at compression level 15 (high compression, slower). The filename includes the current date in YYYY-MM-DD format, producing files like Something-2026-03-22.tar.zst.

  2. Cleanup - find $backdest/ -mtime +2 -delete removes files with a modification time strictly greater than 2 days (48 hours) ago. This means:

    • Today's backup: kept
    • Yesterday's backup: kept
    • Day before yesterday's backup: kept (less than 48h old depending on timing)
    • Older backups: deleted

    To change the retention period, adjust the -mtime value. For example, -mtime +6 keeps roughly 7 days of backups.

For production use, consider adding:

#!/bin/bash
set -euo pipefail

backdest="/mnt/Backup/destination"
backsource="/path/to/dir"
date=$(date "+%F")
logfile="/var/log/backup-dir.log"

# Verify destination is mounted/accessible
if [[ ! -d "$backdest" ]]; then
    echo "$(date '+%F %T') - ERROR: Backup destination not accessible: $backdest" >> "$logfile"
    exit 1
fi

# Create archive
if tar -cv -I "pzstd -15" -f "$backdest/Something-$date.tar.zst" "$backsource" >> "$logfile" 2>&1; then
    echo "$(date '+%F %T') - Backup completed successfully" >> "$logfile"
else
    echo "$(date '+%F %T') - ERROR: Backup failed with exit code $?" >> "$logfile"
    exit 1
fi

# Cleanup old backups
find "$backdest/" -name "*.tar.zst" -mtime +2 -delete
echo "$(date '+%F %T') - Cleanup completed" >> "$logfile"

Key improvements:

  • set -euo pipefail - exit on errors, undefined variables, and pipe failures
  • Destination directory check before writing
  • Error logging with timestamps
  • Cleanup targets only .tar.zst files (avoids deleting unrelated files)

Troubleshooting#

IssueCauseSolution
pzstd: command not foundzstd package not installedInstall zstd package
Archive is 0 bytesSource path does not exist or is emptyVerify backsource path
Old backups not deleted-mtime threshold not reachedCheck file modification times with stat
Disk fullRetention too long or source too largeReduce -mtime value or lower compression level
Permission deniedUser lacks write access to destinationRun as appropriate user or fix permissions

See Also#

Sources#