improve
This commit is contained in:
@@ -5,12 +5,13 @@ set -euo pipefail
|
|||||||
# --- Functions ---
|
# --- Functions ---
|
||||||
|
|
||||||
print_usage() {
|
print_usage() {
|
||||||
echo "Usage: $0 [backup_output_path] [--list file_with_paths] -- <src_dir1> <src_dir2> ..."
|
echo "Usage: $0 [backup_output_path] [--list file_with_paths] [--exclude path] [--exclude-from file] -- <src_dir1> <src_dir2> ..."
|
||||||
echo
|
echo
|
||||||
echo "Examples:"
|
echo "Examples:"
|
||||||
echo " $0 /backup/my_backup.tar.gz -- /home/user /etc"
|
echo " $0 /backup/my_backup.tar.gz -- /home/user /etc"
|
||||||
echo " BACKUP_PATH=/backup/auto.tar.gz $0 --list dirs.txt -- /var/log"
|
echo " BACKUP_PATH=/backup/auto.tar.gz $0 --list dirs.txt -- /var/log"
|
||||||
echo " $0 /mnt/backup/nextcloud_mirror -- /srv/nextcloud"
|
echo " $0 /mnt/backup/nextcloud_mirror -- /srv/nextcloud"
|
||||||
|
echo " $0 /backup.tgz --exclude \"/home/*/.cache\" -- /home"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,19 +20,35 @@ parse_args() {
|
|||||||
local -n _src_dirs=$2
|
local -n _src_dirs=$2
|
||||||
local -n _list_file=$3
|
local -n _list_file=$3
|
||||||
local -n _archive_type=$4
|
local -n _archive_type=$4
|
||||||
|
local -n _exclude_paths=$5
|
||||||
|
local -n _exclude_file=$6
|
||||||
|
|
||||||
local positional=()
|
local positional=()
|
||||||
local in_sources=0
|
local in_sources=0
|
||||||
|
shift 6
|
||||||
|
|
||||||
while [[ $# -gt 4 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "${5}" in
|
case "$1" in
|
||||||
--list)
|
--list)
|
||||||
shift 5
|
shift
|
||||||
_list_file="${1:-}"
|
_list_file="${1:-}"
|
||||||
if [[ -z "$_list_file" || ! -f "$_list_file" ]]; then
|
if [[ -z "$_list_file" || ! -f "$_list_file" ]]; then
|
||||||
echo "Error: list file '$_list_file' not found." >&2
|
echo "Error: list file '$_list_file' not found." >&2
|
||||||
print_usage
|
print_usage
|
||||||
exit 1
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--exclude)
|
||||||
|
shift
|
||||||
|
_exclude_paths+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--exclude-from)
|
||||||
|
shift
|
||||||
|
_exclude_file="$1"
|
||||||
|
if [[ ! -f "$_exclude_file" ]]; then
|
||||||
|
echo "Error: exclude-from file '$_exclude_file' not found." >&2
|
||||||
|
print_usage
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
@@ -41,9 +58,9 @@ parse_args() {
|
|||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [[ $in_sources -eq 1 ]]; then
|
if [[ $in_sources -eq 1 ]]; then
|
||||||
_src_dirs+=("$5")
|
_src_dirs+=("$1")
|
||||||
else
|
else
|
||||||
positional+=("$5")
|
positional+=("$1")
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
@@ -62,7 +79,6 @@ parse_args() {
|
|||||||
if [[ -z "$_target_path" ]]; then
|
if [[ -z "$_target_path" ]]; then
|
||||||
echo "Error: No target path provided and BACKUP_PATH is not set." >&2
|
echo "Error: No target path provided and BACKUP_PATH is not set." >&2
|
||||||
print_usage
|
print_usage
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$_target_path" in
|
case "$_target_path" in
|
||||||
@@ -102,7 +118,6 @@ validate_src_dirs() {
|
|||||||
if [[ ${#_src_dirs[@]} -eq 0 ]]; then
|
if [[ ${#_src_dirs[@]} -eq 0 ]]; then
|
||||||
echo "Error: No valid source directories to back up." >&2
|
echo "Error: No valid source directories to back up." >&2
|
||||||
print_usage
|
print_usage
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,27 +126,47 @@ init_tmp_dir() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count_files() {
|
count_files() {
|
||||||
local src_dirs=("$@")
|
local exclude_args=()
|
||||||
|
local src_dirs=()
|
||||||
|
while [[ "$1" != "--" ]]; do
|
||||||
|
exclude_args+=("$1")
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
shift # skip the "--"
|
||||||
|
src_dirs=("$@")
|
||||||
|
|
||||||
local count=0
|
local count=0
|
||||||
echo "Counting directories: " "${src_dirs[@]}" 1>&2
|
|
||||||
for dir in "${src_dirs[@]}"; do
|
for dir in "${src_dirs[@]}"; do
|
||||||
echo "Counting directory: " "$dir" 1>&2
|
local find_cmd=(find "$dir" -xdev)
|
||||||
for subdir in `find . -maxdepth 2`
|
if [[ ${#exclude_args[@]} -gt 0 ]]; then
|
||||||
count=$((count + $(find "$dir" -xdev | wc -l)))
|
find_cmd+=(\( "${exclude_args[@]}" -prune \) -o -print)
|
||||||
|
fi
|
||||||
|
count=$((count + $("${find_cmd[@]}" | wc -l)))
|
||||||
done
|
done
|
||||||
echo "$count"
|
echo "$count"
|
||||||
}
|
}
|
||||||
|
|
||||||
run_rsync_backup() {
|
run_rsync_backup() {
|
||||||
local src_dirs=("${!1}")
|
local src_dirs=(${!1})
|
||||||
local dest_path="$2"
|
local dest_path="$2"
|
||||||
local file_count="$3"
|
local file_count="$3"
|
||||||
|
local -n exclude_paths=$4
|
||||||
|
local exclude_file="$5"
|
||||||
|
|
||||||
echo "Starting backup..."
|
echo "Starting backup..."
|
||||||
|
|
||||||
|
local rsync_opts=("-Aavx")
|
||||||
|
for e in "${exclude_paths[@]}"; do
|
||||||
|
rsync_opts+=("--exclude=$e")
|
||||||
|
done
|
||||||
|
if [[ -n "$exclude_file" ]]; then
|
||||||
|
rsync_opts+=("--exclude-from=$exclude_file")
|
||||||
|
fi
|
||||||
|
|
||||||
for dir in "${src_dirs[@]}"; do
|
for dir in "${src_dirs[@]}"; do
|
||||||
base="$(basename "$dir")"
|
base="$(basename "$dir")"
|
||||||
dest_dir="$dest_path/$base"
|
dest_dir="$dest_path/$base"
|
||||||
rsync -Aavx "$dir"/ "$dest_dir"/ | pv -ltps "$file_count" > /dev/null
|
rsync "${rsync_opts[@]}" "$dir"/ "$dest_dir"/ | pv -ltps "$file_count" > /dev/null
|
||||||
done
|
done
|
||||||
echo "Rsync completed."
|
echo "Rsync completed."
|
||||||
}
|
}
|
||||||
@@ -160,7 +195,7 @@ compress_backup() {
|
|||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unsupported archive type or no compression." >&2
|
echo "Unsupported archive type or no compression." >&2
|
||||||
return 1
|
print_usage
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
echo "Archive created successfully."
|
echo "Archive created successfully."
|
||||||
@@ -175,29 +210,50 @@ cleanup_tmp_dir() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
echo "Do sync..."
|
||||||
|
sync
|
||||||
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local TARGET_PATH=""
|
local TARGET_PATH=""
|
||||||
local SRC_DIRS=()
|
local SRC_DIRS=()
|
||||||
local LIST_FILE=""
|
local LIST_FILE=""
|
||||||
local ARCHIVE_TYPE="NONE"
|
local ARCHIVE_TYPE="NONE"
|
||||||
|
local EXCLUDE_PATHS=()
|
||||||
|
local EXCLUDE_FILE=""
|
||||||
|
|
||||||
parse_args TARGET_PATH SRC_DIRS LIST_FILE ARCHIVE_TYPE "$@"
|
parse_args TARGET_PATH SRC_DIRS LIST_FILE ARCHIVE_TYPE EXCLUDE_PATHS EXCLUDE_FILE "$@"
|
||||||
load_dirs_from_list_file SRC_DIRS "$LIST_FILE"
|
load_dirs_from_list_file SRC_DIRS "$LIST_FILE"
|
||||||
validate_src_dirs SRC_DIRS
|
validate_src_dirs SRC_DIRS
|
||||||
|
|
||||||
|
local exclude_args=()
|
||||||
|
for e in "${EXCLUDE_PATHS[@]}"; do
|
||||||
|
exclude_args+=( -path "$e" -o )
|
||||||
|
done
|
||||||
|
if [[ -n "$EXCLUDE_FILE" ]]; then
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
[[ -z "$line" || "$line" =~ ^# ]] && continue
|
||||||
|
exclude_args+=( -path "$line" -o )
|
||||||
|
done < "$EXCLUDE_FILE"
|
||||||
|
fi
|
||||||
|
[[ ${#exclude_args[@]} -gt 0 ]] && unset 'exclude_args[${#exclude_args[@]}-1]'
|
||||||
|
|
||||||
local FILE_COUNT
|
local FILE_COUNT
|
||||||
FILE_COUNT=$(count_files "${SRC_DIRS[@]}")
|
FILE_COUNT=$(count_files "${exclude_args[@]}" -- "${SRC_DIRS[@]}")
|
||||||
|
|
||||||
if [[ "$ARCHIVE_TYPE" != "NONE" ]]; then
|
if [[ "$ARCHIVE_TYPE" != "NONE" ]]; then
|
||||||
local TMP_DIR
|
local TMP_DIR
|
||||||
TMP_DIR=$(init_tmp_dir)
|
TMP_DIR=$(init_tmp_dir)
|
||||||
run_rsync_backup SRC_DIRS[@] "$TMP_DIR" "$FILE_COUNT"
|
run_rsync_backup SRC_DIRS[@] "$TMP_DIR" "$FILE_COUNT" EXCLUDE_PATHS "$EXCLUDE_FILE"
|
||||||
compress_backup "$TMP_DIR" "$TARGET_PATH" "$ARCHIVE_TYPE"
|
compress_backup "$TMP_DIR" "$TARGET_PATH" "$ARCHIVE_TYPE"
|
||||||
cleanup_tmp_dir "$TMP_DIR"
|
cleanup_tmp_dir "$TMP_DIR"
|
||||||
else
|
else
|
||||||
mkdir -p "$TARGET_PATH"
|
mkdir -p "$TARGET_PATH"
|
||||||
run_rsync_backup SRC_DIRS[@] "$TARGET_PATH" "$FILE_COUNT"
|
run_rsync_backup SRC_DIRS[@] "$TARGET_PATH" "$FILE_COUNT" EXCLUDE_PATHS "$EXCLUDE_FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
teardown
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Entry Point ---
|
# --- Entry Point ---
|
||||||
|
|||||||
Reference in New Issue
Block a user