#!/bin/bash ## ------------------------------------ ## Made By: Michael Yochpaz (C) 2020 ## https://github.com/MichaelYochpaz/Backup-Script ## Version: 1.2.0 ## License: GPLv3 ## ------------------------------------ ## -------------- Usage --------------- ## The script generates a tar.gz backup file of a folder, and according to user's given arguments, ## can upload it to a cloud service using rclone and remove the local copy. ## ## ------------ Requirments ----------- ## - In order to use the upload feature, rclone must be installed and have at least one cloud service setup in config. ## ------------------------------------ ## ## Usage: backup [-n <name>] [-s <path>] [-e <pattern>]... [-u <path>] [-p <API key>] [-r] [-y] [-v] <path-to-backup> ## ## Options: ## -n <name> Sets the tar.gz file name [default: "backup"] ## -s <path> Path to which the generated backup file will be saved to [default: current working directory] ## -e <pattern> Exclude a pattern (specific files / folders) from being backed up ## -u <path> rclone path to which the backup file will be uploaded to (not providing one will skip the upload process) ## -p <API key> Sends a Pushbullet notification once backup is done ## -r Removes local copy of backup file after it's been uploaded ## -y Skip warnings (Warnings require user input to continue by default) ## -v Uses '-v' option when running tar and rclone ## ## Commands: ## -h Displays this help message and exists. ## ## Examples: ## backup "/home/user/important_stuff" ## backup -u "GDrive:/Backups" -r -y -p "XXXXXXXXXXXXXXXX" "/home/user/important_stuff/" ## backup -n "important-stuff-backup" -s "/home/user/backups" -e "*.pdf" -e "important_stuff/dont_backup_this_folder" "/home/user/important_stuff/" ## ## --------- Configuration ------------ BACKUP_NAME="backup" # Backup file name. date will be added to file name after this string. BACKUP_FOLDER="" # Folder to backup (full path). EXCLUDES=() # Exclusion patterns array. Usage example: ("*.mkv" "*.pdf" "important_stuff/dont_backup_this_folder") SAVE_FOLDER="$PWD" # Folder to save backup file to (full path) RCLONE_FOLDER="" # rclone folder path to upload backup file to. Leave empty to skip the upload process. PUSHBULLET_API_KEY="" # Pusbullet API key for notifications. REMOVE_LOCAL=false # Boolean - Remove local backup file after upload. SKIP_WARNINGS=false # Boolean - Skip warnings. VERBOSE=false # Boolean - Use verbose mode when running tar and rclone. PUSHBULLET_TITLE="Backup Script" # Pusbullet - Notification title. PUSHBULLET_MESSAGE_START="Backup script " # Pushbullet - Notification messages will start with this string, followed by one of the followings: PUSHBULLET_MESSAGE_FINISHED_SUCCESS="finished successfully." # Pusbullet - Message will be shown if the script ran successfully. PUSHBULLET_MESSAGE_FINISHED_ERRORS="finished with errors." # Pusbullet - Message will be shown if the script finished with errors. PUSHBULLET_MESSAGE_FAIL="failed." # Pusbullet - Message will be shown if the script has failed. ## ------------------------------------ usage() { echo "Usage: $(basename $0) [-n <name>] [-s <path>] [-e <pattern>]... [-u <path>] [-p <API key>] [-r] [-y] [-v] <path-to-backup> Use $(basename $0) -h for additional info."; exit 1; } # if there is a Pushbullet API key, send a Pushbullet notification. uses a parameter for message's body pushbullet() { if [ -n "$PUSHBULLET_API_KEY" ]; then curl -u "$PUSHBULLET_API_KEY": https://api.pushbullet.com/v2/pushes -d type=note -d \ title="$PUSHBULLET_TITLE" -d body="$PUSHBULLET_MESSAGE_START$1 " >/dev/null 2>&1; fi } ERROR=false # sets to true if there's an error. used for final exit code of the script. C0='\033[0m' # ANSI - no color C1='\033[0;32m' # ANSI - success - green C2='\033[1;31m' # ANSI - error - red C3='\033[0;36m' # ANSI - information - cyan C4='\033[0;33m' # ANSI - variables/paths - orange while getopts ":n:e:s:u:p:ryvh" arg; do case $arg in n) BACKUP_NAME=${OPTARG} ;; e) EXCLUDES+=("${OPTARG}") ;; s) SAVE_FOLDER=${OPTARG} ;; u) RCLONE_FOLDER=${OPTARG} ;; p) PUSHBULLET_API_KEY=${OPTARG} ;; r) REMOVE_LOCAL=true ;; y) SKIP_WARNINGS=true ;; v) VERBOSE=true ;; h) echo " Usage: $(basename $0) [-n <name>] [-s <path>] [-e <pattern>]... [-u <path>] [-p <API key>] [-r] [-y] [-v] <path-to-backup> Options: -n <name> Sets the tar.gz file name [default: "backup"] -s <path> Path to which the generated backup file will be saved to [default: current working directory] -e <pattern> Exclude a pattern (specific files / folders) from being backed up -u <path> rclone path to which the backup file will be uploaded to (not providing one will skip the upload process) -p <API key> Sends a Pushbullet notification once backup is done -r Removes local copy of backup file after it's been uploaded -y Skip warnings (Warnings require user input to continue by default) -v Uses '-v' option when running tar and rclone Commands: -h Displays this help message and exists. Examples: $(basename $0) \"/home/user/important_stuff\" $(basename $0) -u \"GDrive:/Backups\" -r -y -p \"XXXXXXXXXXXXXXXX\" \"/home/user/important_stuff/\" $(basename $0) -n \"important-stuff-backup\" -s \"/home/user/backups\" -e \"*.pdf\" -e \"important_stuff/dont_backup_this_folder\" \"/home/user/important_stuff/\"" exit 0 ;; *) usage ;; esac done # positional argument - the folder that's going to be backed-up if [[ -n "${@:$OPTIND:1}" ]]; then BACKUP_FOLDER=${@:$OPTIND:1}; fi # if no backup folder was chosen, show usage if [ -z "$BACKUP_FOLDER" ]; then usage; fi # if BACKUP_FOLDER path doesn't exist, show error and exit if [ ! -d $BACKUP_FOLDER ]; then echo -e "${C2}Folder ${C4}$BACKUP_FOLDER ${C2}not found${C0}" pushbullet "$PUSHBULLET_MESSAGE_FAIL" exit 1 fi # if SAVE_FOLDER path doesn't exist, show error and exit if [ ! -d $SAVE_FOLDER ]; then echo -e "${C2}Folder ${C4}$SAVE_FOLDER ${C2}not found${C0}" pushbullet "$PUSHBULLET_MESSAGE_FAIL" exit 1 fi # if BACKUP_FOLDER path ends with a '/', remove it if [ "${BACKUP_FOLDER: -1}" = "/" ]; then BACKUP_FOLDER=${BACKUP_FOLDER%?}; fi # if SAVE_FOLDER path ends with a '/', remove it if [ "${SAVE_FOLDER: -1}" = "/" ]; then SAVE_FOLDER=${SAVE_FOLDER%?}; fi # if REMOVE_LOCAL is set to true, but rclone upload is not used, show a warning. if [ "$REMOVE_LOCAL" = true ] && [ -z "$RCLONE_FOLDER" ] && [] "$SKIP_WARNINGS" = false ]; then read -p "WARNING: '-r' argument to remove local backup file was used, but no rclone path to upload backup flie to beforehand is set. This will result in generating a backup file and deleting it after without it being uploaded anywhere. Would you like to continue (Y/n) ?" -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 0; fi fi # ----- tar ----- echo -e "$(date +"%Y/%m/%d %T") ${C3}Generating tar.gz file"${C0} FILENAME="${BACKUP_NAME}-$(date +%FT%H%M).tar.gz" # generate a temporary file to store EXCLUDES in EXCLUEDS_FILE=$(mktemp /tmp/backup.XXXXXX.txt) if [ ! ${#EXCLUDES[@]} -eq 0 ]; then printf "%s\n" "${EXCLUDES[@]}" > "$EXCLUEDS_FILE"; fi # run tar with or without '-v', according to VERBOSE value if [ "$VERBOSE" = true ]; then tar -cvzf "$SAVE_FOLDER/$FILENAME" -C "$BACKUP_FOLDER/.." -X $EXCLUEDS_FILE "$(basename "$BACKUP_FOLDER")"; \ else tar -czf "$SAVE_FOLDER/$FILENAME" -C "$BACKUP_FOLDER/.." -X $EXCLUEDS_FILE "$(basename "$BACKUP_FOLDER")"; fi # remove temporary file rm $EXCLUEDS_FILE # tar commmand finished successfully (exit code = 0) if [ "$?" = 0 ]; then echo -e "$(date +"%Y/%m/%d %T") ${C1}Backup file generated and saved successfully to ${C4}$SAVE_FOLDER/$FILENAME ($(du -h "$SAVE_FOLDER/$FILENAME" | cut -f1))${C0}" # tar commmand didn't run successfully (exit code != 0) else echo -e "$(date +"%Y/%m/%d %T") ${C2}Backup file generation failed${C0}" # if a file was generated during the (failed) tar process, remove it if [ -f "$SAVE_FOLDER/$FILENAME" ]; then rm "$SAVE_FOLDER/$FILENAME"; fi pushbullet "$PUSHBULLET_MESSAGE_FAIL" exit 1 fi # ----- rclone ----- if [ -n "$RCLONE_FOLDER" ]; then echo -e "$(date +"%Y/%m/%d %T") ${C3}Uploading backup file to ${C4}$RCLONE_FOLDER${C0}" # run rclone with or without '-v', according to VERBOSE value if [ "$VERBOSE" = true ]; then rclone copy "$SAVE_FOLDER/$FILENAME" -v "$RCLONE_FOLDER"; else rclone copy "$SAVE_FOLDER/$FILENAME" "$RCLONE_FOLDER"; fi # rclone commmand finished successfully (exit code = 0) if [ "$?" = 0 ]; then echo -e "$(date +"%Y/%m/%d %T") ${C1}Backup file uploaded successfully${C0}" # rclone command didn't run successfully (exit code != 0) else ERROR=true echo -e "$(date +"%Y/%m/%d %T") ${C2}Upload failed${C0}" if [ "$REMOVE_LOCAL" = true ] && [ "$SKIP_WARNINGS" = false ]; then read -p "WARNING: Would you like to continute and remove local copy of the backup file even though upload wasn't successful (Y/n) ? " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo -e "$(date +"%Y/%m/%d %T") ${C2}Script finished with errors${C0}" exit 1 fi fi fi fi # remove local backup if REMOVE_LOCAL setting used if [ "$REMOVE_LOCAL" = true ]; then rm "$SAVE_FOLDER/$FILENAME" echo -e "$(date +"%Y/%m/%d %T") ${C1}Local file removed${C0}" fi # print, send Pushbullet notification (if used), and exit using correct code according to ERROR's value if [ "$ERROR" = false ]; then echo -e "$(date +"%Y/%m/%d %T") ${C1}Script finished successfully${C0}" pushbullet "$PUSHBULLET_MESSAGE_FINISHED_SUCCESS" exit 0; else echo -e "$(date +"%Y/%m/%d %T") ${C2}Script finished with errors${C0}" pushbullet "$PUSHBULLET_MESSAGE_FINISHED_ERRORS" exit 1 fi