Skip to content

Instantly share code, notes, and snippets.

@Urpagin
Created November 11, 2025 22:31
Show Gist options
  • Select an option

  • Save Urpagin/229726e00e693a596ce19d5123d52844 to your computer and use it in GitHub Desktop.

Select an option

Save Urpagin/229726e00e693a596ce19d5123d52844 to your computer and use it in GitHub Desktop.
Archives a directory simply and efficiently (but slowly mx=9). (output is .tar.7z)
#!/usr/bin/env bash
# Author: Urpagin
# Date: 2025-11-11 around 20:00.
# License: MIT
# Description: - Makes a backup of an entire directory (including hidden files)
# and conserving permissions and other metadata using the tar algo first.
# - Creates .tar.7z files and uses maximum 7z compression.
# - CLI flags for a filename, appends the date after.
# E.g., <name>_YYYY-MM-DD_HH-MM-SS.tar.7z
# Flaws: No functions + I'm not great heh + surely ridden with unthought edges cases.
set -euo pipefail
usage() {
cat << EOF
USAGE:
$0 -d <directory to backup> -n <name of the archive> [-y]
DESCRIPTION:
Makes a .tar.7z maximally compressed backup of the input directory.
Saves it as <name>_YYYY-MM-DD_HH-MM-SS.tar.7z in the current directory.
-y does not prompt the user for confirmation.
EOF
exit 1
}
# The dir to backup.
_target_dir=''
# The dir where to save the archive.
_archive_dir="$(pwd)"
# The name of the archive.
_archive_suffix=''
_y_arg='false'
_REQUIRED_COMMANDS=( getopts tar 7z )
for cmd in "${_REQUIRED_COMMANDS[@]}"; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Command $cmd is required." >&2
exit 1
fi
done
while getopts ":d:n:y" opt; do
case "$opt" in
d)
_target_dir="$OPTARG"
;;
n)
_archive_suffix="$OPTARG"
;;
y)
_y_arg=true
;;
\?)
echo "Unknown option: -$OPTARG" >&2
usage
;;
:)
echo "Option -$OPTARG requires an argument." >&2
usage
;;
esac
done
# Drop the parsed options from ""
shift $((OPTIND - 1))
# Validation
[[ -z "$_target_dir" ]] && { echo "Missing -d <directory>"; usage; }
[[ ! -d "$_target_dir" ]] && { echo "Target directory '$_target_dir' not found."; usage; }
[[ -z "$_archive_suffix" ]] && { echo "Missing -n <name of the archive>"; usage; }
# E.g., test_2025-11-23.tar.7z
_archive_filename="${_archive_suffix}_$(date +%F_%H-%M-%S).tar.7z"
# E.g., /home/user/Documents/test_2025-11-23.tar.7z
_archive_path="${_archive_dir}/${_archive_filename}"
if [[ -e "$_archive_path" ]]; then
echo "Archive already exists: $_archive_path" >&2
exit 1
fi
_prompt_user() {
echo 'Calculating size...'
_target_dir_size=$(du -sh -- "$_target_dir" | cut -f 1)
printf 'Backing up:\n'%s' (%s) -> '%s'\n' "$_target_dir" "$_target_dir_size" "$_archive_path"
# Ask user for confirmation
# https://stackoverflow.com/questions/1885525/how-do-i-prompt-a-user-for-confirmation-in-bash-script
read -p "Back up? (y/N): " -n 1 -r; echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo 'Aborted.'
exit 0
fi
}
# No prompts if -y
[[ "$_y_arg" == true ]] || _prompt_user
# Create the archive
tar cf - --exclude="$_archive_filename" -C "$_target_dir" . | \
7z a -t7z -mx=9 -si"archive.tar" "$_archive_path"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment