Timestamped tar.gz backup that keeps the newest N
Archive a directory with a sortable timestamp and delete older backups beyond a retention count.
- Bash
- GreenSnippets
- MIT
#!/usr/bin/env bash
set -euo pipefail
SRC="${1:?usage: backup.sh <source-dir> <backup-dir> [keep]}"
DEST="${2:?usage: backup.sh <source-dir> <backup-dir> [keep]}"
KEEP="${3:-7}"
mkdir -p "$DEST"
name="$(basename "$SRC")-$(date +%Y%m%d-%H%M%S).tar.gz"
tar -czf "$DEST/$name" -C "$(dirname "$SRC")" "$(basename "$SRC")"
echo "Created $DEST/$name"
# Newest first; skip the first $KEEP, delete the rest.
ls -1t "$DEST"/"$(basename "$SRC")"-*.tar.gz | tail -n +"$((KEEP + 1))" | while read -r old; do
rm -- "$old"
echo "Removed $old"
doneHow it works
ISO-style timestamps (20260115-093000) sort alphabetically in date order, so ls shows the newest last. After creating the archive, the script lists existing backups newest first and removes everything beyond KEEP.
Test with echo in front of rm first. Backups on the same disk do not protect against disk failure, so copy them off the machine too. This script has been reviewed but not run through an automated test; it assumes GNU tar and file names without newlines.
This snippet has been reviewed but was not executed by an automated test. Test it in your own environment before relying on it.
Related snippets
- Bash
Parse command-line flags with getopts
Handle -v, -o FILE and -h in a bash script with getopts and a usage message.
- Python Tested
Command-line tool skeleton with argparse
A small CLI with a positional argument, flags, a main function and proper exit codes.
- Bash
Delete local Git branches that are already merged
Clean up merged local branches safely, excluding main, master, develop and the current branch.
- Bash
Safe header for Bash scripts
Fail fast on errors, unset variables and broken pipes, and clean up temp files with a trap.

