Rsync Script for multi folder backup

Linux Rsync Backup

This is linux bash script what allows to sync mutliple source folders into one.
You can also exclude files and folder as you would do with Rsync, just pass it all with -e flag
-r is root folder, if you want to set root folder from where all your folders will be backing up, you need to pass them in -f flag
-f flag can be used on its own, by passing all the folder paths devided with comma inside double quotes
- d is just destination folder ( destination folder will be created if does not exists yet)

#!/bin/bash
# Define default values
root_source=""
source_folders=()
dest_folder=""
exclude_patterns=""
exclusions=()
# Function to display usage information
usage() {
    echo 'Usage: $0 -r  -f "" -d  [-e ""]'
    echo 'Example 1 (root folder and multiple folders in it):' 
    echo '$0 -r /mnt/drive -f "opt,root,home" -d /dest/folder/'
    echo 'Example 2 (multiple folder paths synced to one destination):'
    echo '$0 -f "/mnt/drive/opt,/mnt/drive/root,/mnt/drive/home" -d /dest/folder/'
    echo 'Example 3 (with exclude patterns):'
    echo '$0 -f "/mnt/drive/opt,/mnt/drive/root,/mnt/drive/home" -d /dest/folder/ -e "*.tmp,*.log"'
    exit 1
}

# Function to enable tab completion for file paths
enable_tab_completion() {
    local cur prev
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    case "${prev}" in
        -r) # Tab complete for root_source
            COMPREPLY=( $(compgen -d "${cur}" ) );;
        -d) # Tab complete for dest_folder
            COMPREPLY=( $(compgen -d "${cur}" ) );;
        *) # Default tab completion
            COMPREPLY=()
    esac
    return 0
}

# Register tab completion function for the script
complete -F enable_tab_completion "$0"

# Parse command-line options
while getopts r:f:d:e: flag
do
    case "${flag}" in
        r) root_source="$OPTARG";;
        f) IFS=',' read -r -a source_folders <<< "$OPTARG";;
        e) IFS=',' read -r -a exclude_patterns <<< "$OPTARG";;
        d) dest_folder="$OPTARG";;
        :) echo "Option -$OPTARG requires an argument."; usage;;
        \?) echo "Invalid option: -$OPTARG"; usage;;
    esac
done

if [ ${#exclude_patterns[@]} -gt 0 ]; then
    for pattern in "${exclude_patterns[@]}"; do
        exclusions+=("--exclude=${pattern// /}")
    done
fi

# Function to perform rsync for each source folder
perform_rsync() {
    src="$1"
    dest="$2"
    rsync -ah --stats "${exclusions[@]}" "$src" "$dest"
    echo "Rsync summary for: $src"
    echo
}
mkdir -p "$dest_folder" 2>/dev/null
# Check if root_source is provided
if [ -z "$root_source" ]; then
    # Handle case where root_source is included in each source folder path
    for folder in "${source_folders[@]}"; do
        perform_rsync "$folder" "$dest_folder" &
    done
elif [ -n "$root_source" ]; then
    # Check if source_folders and dest_folder are provided
    if [ ${#source_folders[@]} -eq 0 ] || [ -z "$dest_folder" ]; then
        echo "Error: Missing required option(s)."
        usage
    fi
    # Iterate over each source folder and perform rsync in parallel
    for folder in "${source_folders[@]}"; do
        full_src="${root_source%/}/${folder%/}"  # Ensure trailing slash is removed from source folder
        perform_rsync "$full_src" "$dest_folder" &
    done
else
    echo "Error: Missing required option(s)."
    usage
fi
# Wait for all background jobs to finish
wait
echo "All Rsync jobs are done!"