Skip to content

Commit b65b314

Browse files
authored
Merge pull request #34 from buildplan/improved_term_prompts
Improved prompts with colours in terminal for restore and test flags
2 parents 372382c + 6c69ef5 commit b65b314

File tree

4 files changed

+115
-79
lines changed

4 files changed

+115
-79
lines changed

README.md

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ To run the backup automatically, edit the root crontab.
184184
185185
```ini
186186
# =================================================================
187-
# Configuration for rsync Backup Script v0.28
187+
# Configuration for rsync Backup Script v0.29
188188
# =================================================================
189189
# !! IMPORTANT !! Set file permissions to 600 (chmod 600 backup.conf)
190190
@@ -301,7 +301,7 @@ END_EXCLUDES
301301
302302
```bash
303303
#!/bin/bash
304-
# ===================== v0.28 - 2025.08.12 ========================
304+
# ===================== v0.29 - 2025.08.13 ========================
305305
#
306306
# =================================================================
307307
# SCRIPT INITIALIZATION & SETUP
@@ -311,6 +311,25 @@ umask 077
311311

312312
HOSTNAME=$(hostname -s)
313313

314+
# --- Color Palette ---
315+
if [ -t 1 ]; then
316+
C_RESET='\e[0m'
317+
C_BOLD='\e[1m'
318+
C_DIM='\e[2m'
319+
C_RED='\e[0;31m'
320+
C_GREEN='\e[0;32m'
321+
C_YELLOW='\e[0;33m'
322+
C_CYAN='\e[0;36m'
323+
else
324+
C_RESET=''
325+
C_BOLD=''
326+
C_DIM=''
327+
C_RED=''
328+
C_GREEN=''
329+
C_YELLOW=''
330+
C_CYAN=''
331+
fi
332+
314333
# Check if the script is being run as root
315334
if (( EUID != 0 )); then
316335
echo "❌ This script must be run as root or with sudo." >&2
@@ -514,20 +533,19 @@ run_preflight_checks() {
514533
local mode=${1:-backup}; local test_mode=false
515534
if [[ "$mode" == "test" ]]; then test_mode=true; fi
516535
local check_failed=false
517-
if [[ "$test_mode" == "true" ]]; then echo "--- Checking required commands..."; fi
536+
if [[ "$test_mode" == "true" ]]; then printf "${C_BOLD}--- Checking required commands...${C_RESET}\n"; fi
518537
for cmd in "${REQUIRED_CMDS[@]}"; do
519538
if ! command -v "$cmd" &>/dev/null; then echo "❌ FATAL: Required command '$cmd' not found." >&2; check_failed=true; fi
520539
done
521540
if [[ "$check_failed" == "true" ]]; then exit 10; fi
522-
if [[ "$test_mode" == "true" ]]; then echo "✅ All required commands are present."; fi
523-
if [[ "$test_mode" == "true" ]]; then echo "--- Checking SSH connectivity..."; fi
524-
541+
if [[ "$test_mode" == "true" ]]; then printf "${C_GREEN}✅ All required commands are present.${C_RESET}\n"; fi
542+
if [[ "$test_mode" == "true" ]]; then printf "${C_BOLD}--- Checking SSH connectivity...${C_RESET}\n"; fi
525543
# Quick preflight connectivity "ping": short 10s timeout for fail-fast behaviour
526544
if ! ssh "${SSH_OPTS_ARRAY[@]}" -o BatchMode=yes -o ConnectTimeout=10 "$BOX_ADDR" 'exit' 2>/dev/null; then
527545
local err_msg="Unable to SSH into $BOX_ADDR. Check keys and connectivity."
528546
if [[ "$test_mode" == "true" ]]; then echo "$err_msg"; else send_notification "❌ SSH FAILED: ${HOSTNAME}" "x" "${NTFY_PRIORITY_FAILURE}" "failure" "$err_msg"; fi; exit 6
529547
fi
530-
if [[ "$test_mode" == "true" ]]; then echo "✅ SSH connectivity OK."; fi
548+
if [[ "$test_mode" == "true" ]]; then printf "${C_GREEN}✅ SSH connectivity OK.${C_RESET}\n"; fi
531549
if [[ "${RECYCLE_BIN_ENABLED:-false}" == "true" ]]; then
532550
local remote_recycle_path="${BOX_DIR}${RECYCLE_BIN_DIR}"
533551
if ! ssh "${SSH_OPTS_ARRAY[@]}" -o BatchMode=yes -o ConnectTimeout=10 "$BOX_ADDR" "ls -d \"$remote_recycle_path\"" >/dev/null 2>&1; then
@@ -538,7 +556,7 @@ run_preflight_checks() {
538556
fi
539557
fi
540558
if [[ "$mode" != "restore" ]]; then
541-
if [[ "$test_mode" == "true" ]]; then echo "--- Checking backup directories..."; fi
559+
if [[ "$test_mode" == "true" ]]; then printf "${C_BOLD}--- Checking backup directories...${C_RESET}\n"; fi
542560
local DIRS_ARRAY; read -ra DIRS_ARRAY <<< "$BACKUP_DIRS"
543561
for dir in "${DIRS_ARRAY[@]}"; do
544562
if [[ ! -d "$dir" ]] || [[ "$dir" != */ ]]; then
@@ -559,21 +577,21 @@ run_preflight_checks() {
559577
if [[ "$test_mode" == "true" ]]; then echo "❌ FATAL: $err_msg"; else send_notification "❌ Backup FAILED: ${HOSTNAME}" "x" "${NTFY_PRIORITY_FAILURE}" "failure" "FATAL: $err_msg"; fi; exit 2
560578
fi
561579
done
562-
if [[ "$test_mode" == "true" ]]; then echo "✅ All backup directories are valid."; fi
563-
if [[ "$test_mode" == "true" ]]; then echo "--- Checking local disk space..."; fi
564-
local required_space_kb=102400 # 100MB in KB
580+
if [[ "$test_mode" == "true" ]]; then printf "${C_GREEN}✅ All backup directories are valid.${C_RESET}\n"; fi
581+
if [[ "$test_mode" == "true" ]]; then printf "${C_BOLD}--- Checking local disk space...${C_RESET}\n"; fi
582+
local required_space_kb=102400
565583
local available_space_kb
566584
available_space_kb=$(df --output=avail "$(dirname "${LOG_FILE}")" | tail -n1)
567585
if [[ "$available_space_kb" -lt "$required_space_kb" ]]; then
568586
local err_msg="Insufficient disk space in $(dirname "${LOG_FILE}") to guarantee logging. ($((available_space_kb / 1024))MB available)"
569587
if [[ "$test_mode" == "true" ]]; then echo "❌ FATAL: $err_msg"; else send_notification "❌ Backup FAILED: ${HOSTNAME}" "x" "${NTFY_PRIORITY_FAILURE}" "failure" "FATAL: $err_msg"; fi
570588
exit 7
571589
fi
572-
if [[ "$test_mode" == "true" ]]; then echo "✅ Local disk space OK."; fi
590+
if [[ "$test_mode" == "true" ]]; then printf "${C_GREEN}✅ Local disk space OK.${C_RESET}\n"; fi
573591
fi
574592
}
575593
run_restore_mode() {
576-
echo "--- RESTORE MODE ACTIVATED ---"
594+
printf "${C_BOLD}${C_CYAN}--- RESTORE MODE ACTIVATED ---${C_RESET}\n"
577595
run_preflight_checks "restore"
578596
local DIRS_ARRAY; read -ra DIRS_ARRAY <<< "$BACKUP_DIRS"
579597
local RECYCLE_OPTION="[ Restore from Recycle Bin ]"
@@ -582,7 +600,7 @@ run_restore_mode() {
582600
all_options+=("$RECYCLE_OPTION")
583601
fi
584602
all_options+=("Cancel")
585-
echo "Available backup sets to restore from:"
603+
printf "${C_YELLOW}Available backup sets to restore from:${C_RESET}\n"
586604
select dir_choice in "${all_options[@]}"; do
587605
if [[ -n "$dir_choice" ]]; then break;
588606
else echo "Invalid selection. Please try again."; fi
@@ -593,27 +611,27 @@ run_restore_mode() {
593611
local restore_path=""
594612
local is_full_directory_restore=false
595613
if [[ "$dir_choice" == "$RECYCLE_OPTION" ]]; then
596-
echo "--- Browse Recycle Bin ---"
614+
printf "${C_BOLD}${C_CYAN}--- Browse Recycle Bin ---${C_RESET}\n"
597615
local remote_recycle_path="${BOX_DIR%/}/${RECYCLE_BIN_DIR%/}"
598616
local date_folders
599617
date_folders=$(ssh "${SSH_OPTS_ARRAY[@]}" "${SSH_DIRECT_OPTS[@]}" "$BOX_ADDR" "ls -1 \"$remote_recycle_path\"" 2>/dev/null) || true
600618
if [[ -z "$date_folders" ]]; then
601619
echo "❌ No dated folders found in the recycle bin. Nothing to restore." >&2
602620
return 1
603621
fi
604-
echo "Select a date to browse:"
622+
printf "${C_YELLOW}Select a backup run (date_time) to browse:${C_RESET}\n"
605623
select date_choice in $date_folders "Cancel"; do
606624
if [[ "$date_choice" == "Cancel" ]]; then echo "Restore cancelled."; return 0;
607625
elif [[ -n "$date_choice" ]]; then break;
608626
else echo "Invalid selection. Please try again."; fi
609627
done
610628
local remote_date_path="${remote_recycle_path}/${date_choice}"
611-
echo "--- Files available from ${date_choice} (showing first 20) ---"
629+
printf "${C_BOLD}--- Files available from ${date_choice} (showing first 20) ---${C_RESET}\n"
612630
local remote_listing_source="${BOX_ADDR}:${remote_date_path}/"
613631
rsync -r -n --out-format='%n' -e "$SSH_CMD" "$remote_listing_source" . 2>/dev/null | head -n 20 || echo "No files found for this date."
614-
echo "--------------------------------------------------------"
615-
local specific_path
616-
read -p "Enter the full original path of the item to restore (e.g., home/user/file.txt): " specific_path
632+
printf "${C_BOLD}--------------------------------------------------------${C_RESET}\n"
633+
printf "${C_YELLOW}Enter the full original path of the item to restore (e.g., home/user/file.txt): ${C_RESET}"
634+
read -r specific_path
617635
specific_path=$(echo "$specific_path" | sed 's#^/##')
618636
if [[ -z "$specific_path" ]]; then echo "❌ Path cannot be empty. Aborting."; return 1; fi
619637
full_remote_source="${BOX_ADDR}:${remote_date_path}/${specific_path}"
@@ -623,23 +641,24 @@ run_restore_mode() {
623641
fi
624642
default_local_dest="/${specific_path}"
625643
item_for_display="(from Recycle Bin) '${specific_path}'"
626-
elif [[ "$dir_choice" == "Cancel" ]]; then
644+
elif [[ "$dir_choice" == "Cancel" ]]; then
627645
echo "Restore cancelled."
628646
return 0
629647
else
630648
item_for_display="the entire directory '${dir_choice}'"
631649
while true; do
632-
local choice_prompt=$'\nRestore the entire directory or a specific file/subfolder? [entire/specific]: '
633-
read -p "$choice_prompt" choice
650+
printf "\n${C_YELLOW}Restore the entire directory or a specific file/subfolder? [entire/specific]: ${C_RESET}"
651+
read -r choice
634652
case "$choice" in
635653
entire)
636654
is_full_directory_restore=true
637655
break
638656
;;
639657
specific)
640658
local specific_path_prompt
641-
printf -v specific_path_prompt "Enter the path relative to '%s' to restore: " "$dir_choice"
642-
read -ep "$specific_path_prompt" specific_path
659+
printf -v specific_path_prompt "Enter the path relative to '%s' to restore: " "$dir_choice"
660+
printf "${C_YELLOW}%s${C_RESET}" "$specific_path_prompt"
661+
read -er specific_path
643662
specific_path=$(echo "$specific_path" | sed 's#^/##')
644663
if [[ -n "$specific_path" ]]; then
645664
restore_path="$specific_path"
@@ -660,17 +679,16 @@ run_restore_mode() {
660679
default_local_dest=$(echo "$dir_choice" | sed 's#/\./#/#')
661680
fi
662681
fi
663-
local final_dest
664-
local dest_prompt
665-
printf -v dest_prompt "\nEnter the destination path.\nPress [Enter] to use the original location (%s): " "$default_local_dest"
666-
read -p "$dest_prompt" final_dest
682+
local final_dest
683+
printf "\n${C_YELLOW}Enter the destination path.\n${C_DIM}Press [Enter] to use the original location (%s):${C_RESET} " "$default_local_dest"
684+
read -r final_dest
667685
: "${final_dest:=$default_local_dest}"
668686
local extra_rsync_opts=()
669687
local dest_user=""
670688
if [[ "$final_dest" == /home/* ]]; then
671689
dest_user=$(echo "$final_dest" | cut -d/ -f3)
672690
if [[ -n "$dest_user" ]] && id -u "$dest_user" &>/dev/null; then
673-
echo "ℹ️ Home directory detected. Restored files will be owned by '${dest_user}'."
691+
printf "${C_CYAN}ℹ️ Home directory detected. Restored files will be owned by '${dest_user}'.${C_RESET}\n"
674692
extra_rsync_opts+=("--chown=${dest_user}:${dest_user}")
675693
else
676694
dest_user=""
@@ -696,34 +714,34 @@ run_restore_mode() {
696714
if [[ "$dest_created" == "true" && "${is_full_directory_restore:-false}" == "true" ]]; then
697715
chmod 700 "$final_dest"; log_message "Set permissions to 700 on newly created restore directory: $final_dest"
698716
fi
699-
echo "Restore destination is set to: $final_dest"
700-
echo ""; echo "--- PERFORMING DRY RUN. NO FILES WILL BE CHANGED. ---"
717+
printf "Restore destination is set to: ${C_BOLD}%s${C_RESET}\n" "$final_dest"
718+
printf "\n${C_BOLD}${C_YELLOW}--- PERFORMING DRY RUN. NO FILES WILL BE CHANGED. ---${C_RESET}\n"
701719
log_message "Starting restore dry-run of ${item_for_display} from ${full_remote_source} to ${final_dest}"
702720
local rsync_restore_opts=(-avhi --progress --exclude-from="$EXCLUDE_FILE_TMP" -e "$SSH_CMD")
703721
if ! rsync "${rsync_restore_opts[@]}" "${extra_rsync_opts[@]}" --dry-run "$full_remote_source" "$final_dest"; then
704722
echo "❌ DRY RUN FAILED. Rsync reported an error. Aborting." >&2; return 1
705723
fi
706-
echo "--- DRY RUN COMPLETE ---"
724+
printf "${C_BOLD}${C_GREEN}--- DRY RUN COMPLETE ---${C_RESET}\n"
707725
local confirmation
708726
while true; do
709-
local confirmation_prompt
710-
printf -v confirmation_prompt "\nAre you sure you want to proceed with restoring %s to '%s'? [yes/no]: " "$item_for_display" "$final_dest"
711-
read -p "$confirmation_prompt" confirmation
727+
printf "\n${C_YELLOW}Are you sure you want to proceed with restoring %s to '%s'? [yes/no]: ${C_RESET}" "$item_for_display" "$final_dest"
728+
read -r confirmation
729+
712730
case "$confirmation" in
713731
yes) break ;;
714732
no) echo "Restore aborted by user." ; return 0 ;;
715733
*) echo "Please answer yes or no." ;;
716734
esac
717735
done
718-
echo -e "\n--- PROCEEDING WITH RESTORE... ---"
736+
printf "\n${C_BOLD}--- PROCEEDING WITH RESTORE... ---${C_RESET}\n"
719737
log_message "Starting REAL restore of ${item_for_display} from ${full_remote_source} to ${final_dest}"
720738
if rsync "${rsync_restore_opts[@]}" "${extra_rsync_opts[@]}" "$full_remote_source" "$final_dest"; then
721739
log_message "Restore completed successfully."
722-
echo "✅ Restore of $item_for_display to '$final_dest' completed successfully."
740+
printf "${C_GREEN}✅ Restore of %s to '%s' completed successfully.${C_RESET}\n" "$item_for_display" "$final_dest"
723741
send_notification "✅ Restore SUCCESS: ${HOSTNAME}" "white_check_mark" "${NTFY_PRIORITY_SUCCESS}" "success" "Successfully restored ${item_for_display} to ${final_dest}"
724742
else
725743
log_message "Restore FAILED with rsync exit code $?."
726-
echo "❌ Restore FAILED. Check the rsync output and log for details."
744+
printf "${C_RED}❌ Restore FAILED. Check the rsync output and log for details.${C_RESET}\n"
727745
send_notification "❌ Restore FAILED: ${HOSTNAME}" "x" "${NTFY_PRIORITY_FAILURE}" "failure" "Restore of ${item_for_display} to ${final_dest} failed."
728746
return 1
729747
fi

backup.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# =================================================================
2-
# Configuration for rsync Backup Script v0.28
2+
# Configuration for rsync Backup Script v0.29
33
# =================================================================
44
# !! IMPORTANT !! Set file permissions to 600 (chmod 600 backup.conf)
55

0 commit comments

Comments
 (0)