Skip to content

Instantly share code, notes, and snippets.

@tiwiex
Last active September 24, 2025 14:46
Show Gist options
  • Save tiwiex/a4ddaffb253d44584b832aa5810083a5 to your computer and use it in GitHub Desktop.
Save tiwiex/a4ddaffb253d44584b832aa5810083a5 to your computer and use it in GitHub Desktop.
Frappe to Zip Backup
#!/bin/bash
# ================================================
# backup_copy_frappe_zip.git
# Backs up all Frappe sites (with files)
# Compresses each backup into a single ZIP per site
# Supports multiple frappe-bench folders as input
# ================================================
backup_dir="$HOME/frappe-backups"
force_backup=false
bench_folders=()
# Argument handling
if [[ "$1" == "--force" || "$1" == "-f" ]]; then
force_backup=true
shift
fi
# Check for at least one frappe-bench folder
if [[ $# -eq 0 ]]; then
echo -e "\n❌ No frappe-bench folders provided.\n"
echo "πŸ“˜ USAGE:"
echo " ./backup_copy_frappe_zip.git [--force|-f] <frappe-bench-folder1> <frappe-bench-folder2> ..."
echo ""
echo "πŸ“Œ EXAMPLE:"
echo " ./backup_copy_frappe_zip.git -f frappe-bench-dev frappe-bench"
echo ""
echo " This script will back up all sites (except 'assets') under each 'sites' folder in the paths:"
echo " \$HOME/<frappe-bench-folder>/sites"
echo " Backups will be stored in: $backup_dir"
exit 1
fi
# Loop through each frappe-bench folder passed as argument
for folder in "$@"; do
sites_dir="$HOME/$folder/sites"
echo "πŸ“‚ Checking folder: $sites_dir"
if [[ ! -d "$sites_dir" ]]; then
echo " Folder not found: $sites_dir. Skipping..."
continue
fi
cd "$sites_dir" || continue
# Loop through all site folders except 'assets'
for site in $(ls -l | grep '^d' | awk '{print $9}' | grep -v '^assets$'); do
echo "πŸ”„ Processing site: $site"
# Skip backup if already exists for today unless forced
today=$(date +%Y%m%d)
if ! $force_backup && ls "$site/private/backups/" | grep -q "^${today}"; then
echo "⏩ Backup already exists for $site today. Skipping..."
continue
fi
echo " Backing up site: $site with files..."
bench --site "$site" backup --with-files
# Find latest backup prefix
latest_prefix=$(ls "$site/private/backups/" | grep "${site//./_}" | cut -d'-' -f1 | sort | tail -n1)
echo "πŸ“¦ Packaging $latest_prefix for $site..."
# Replace dots with underscores for safe filenames
site_safe=${site//./_}
zip_path="$backup_dir/${latest_prefix}-${site}_all.zip"
zip -j "$zip_path" \
"$site/private/backups/${latest_prefix}-${site_safe}-database.sql.gz" \
"$site/private/backups/${latest_prefix}-${site_safe}-files.tar" \
"$site/private/backups/${latest_prefix}-${site_safe}-private-files.tar" \
"$site/private/backups/${latest_prefix}-${site_safe}-site_config_backup.json"
echo "βœ… Created ZIP: $zip_path"
done
done
echo -e "\nπŸŽ‰ All requested sites processed. Backups saved to: $backup_dir"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment