Design and implement user-friendly, menu-driven command-line interfaces for installation scripts that guide users through configuration choices and provide clear feedback throughout the installation process.
Task Overview
This task focuses on creating intuitive, interactive installation experiences that make complex deployments accessible to users of all technical levels while maintaining the flexibility needed for advanced configurations.
#!/bin/bash
show_welcome() {
clear
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ Application Installer ║"
echo "║ Version 1.0.0 ║"
echo "╠══════════════════════════════════════════════════════════════╣"
echo "║ ║"
echo "║ This installer will guide you through the setup process ║"
echo "║ for your application. You can exit at any time with Ctrl+C ║"
echo "║ ║"
echo "║ Estimated installation time: 5-10 minutes ║"
echo "║ Required disk space: 500MB ║"
echo "║ ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
read -p "Press Enter to continue or Ctrl+C to exit..."
}
show_menu() {
local title="$1"
shift
local options=("$@")
echo ""
echo "┌─ $title ─────────────────────────────────────────────────────┐"
echo "│ │"
for i in "${!options[@]}"; do
printf "│ %d) %-54s │\n" $((i+1)) "${options[$i]}"
done
echo "│ │"
echo "│ q) Quit installer │"
echo "│ h) Help │"
echo "└──────────────────────────────────────────────────────────────┘"
echo ""
}
get_menu_choice() {
local max_choice=$1
local choice
while true; do
read -p "Enter your choice [1-$max_choice, q, h]: " choice
case $choice in
[1-9]|[1-9][0-9])
if [ "$choice" -ge 1 ] && [ "$choice" -le "$max_choice" ]; then
return $choice
else
echo "Invalid choice. Please enter a number between 1 and $max_choice."
fi
;;
q|Q)
echo "Installation cancelled by user."
exit 0
;;
h|H)
show_help
;;
*)
echo "Invalid input. Please enter a number, 'q' to quit, or 'h' for help."
;;
esac
done
}
validate_port() {
local port=$1
# Check if it's a number
if ! [[ "$port" =~ ^[0-9]+$ ]]; then
echo "Error: Port must be a number"
return 1
fi
# Check range
if [ "$port" -lt 1024 ] || [ "$port" -gt 65535 ]; then
echo "Error: Port must be between 1024 and 65535"
return 1
fi
# Check if port is in use
if netstat -ln | grep -q ":$port "; then
echo "Warning: Port $port appears to be in use"
read -p "Continue anyway? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
return 1
fi
fi
return 0
}
get_validated_input() {
local prompt="$1"
local validator="$2"
local default="$3"
local value
while true; do
if [ -n "$default" ]; then
read -p "$prompt [$default]: " value
value=${value:-$default}
else
read -p "$prompt: " value
fi
if [ -z "$value" ] && [ -z "$default" ]; then
echo "This field is required. Please enter a value."
continue
fi
if $validator "$value"; then
echo "$value"
return 0
fi
echo "Please try again."
done
}
show_progress() {
local current=$1
local total=$2
local description="$3"
local width=50
local percentage=$((current * 100 / total))
local filled=$((current * width / total))
local empty=$((width - filled))
printf "\r["
printf "%*s" $filled | tr ' ' '█'
printf "%*s" $empty | tr ' ' '░'
printf "] %d%% - %s" $percentage "$description"
if [ $current -eq $total ]; then
echo ""
fi
}
run_with_progress() {
local command="$1"
local description="$2"
local log_file="/tmp/install_progress.log"
echo "Starting: $description"
# Run command in background and capture PID
$command > "$log_file" 2>&1 &
local pid=$!
# Show spinner while command runs
local spin='-\|/'
local i=0
while kill -0 $pid 2>/dev/null; do
i=$(( (i+1) %4 ))
printf "\r${spin:$i:1} $description..."
sleep 0.1
done
# Wait for command to complete and get exit code
wait $pid
local exit_code=$?
if [ $exit_code -eq 0 ]; then
printf "\r✓ $description completed\n"
else
printf "\r✗ $description failed\n"
echo "Error details:"
cat "$log_file"
return $exit_code
fi
}
show_configuration_summary() {
echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ Configuration Summary ║"
echo "╠══════════════════════════════════════════════════════════════╣"
echo "║ ║"
printf "║ Application Name: %-38s ║\n" "$APP_NAME"
printf "║ Installation Path: %-37s ║\n" "$INSTALL_PATH"
printf "║ Server Port: %-45s ║\n" "$SERVER_PORT"
printf "║ Database Type: %-43s ║\n" "$DATABASE_TYPE"
printf "║ Service User: %-44s ║\n" "$SERVICE_USER"
echo "║ ║"
echo "╠══════════════════════════════════════════════════════════════╣"
echo "║ ║"
echo "║ The installer will now proceed with these settings. ║"
echo "║ This process may take several minutes to complete. ║"
echo "║ ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
read -p "Proceed with installation? [Y/n]: " confirm
if [[ "$confirm" =~ ^[Nn]$ ]]; then
echo "Installation cancelled by user."
exit 0
fi
}
# macOS-specific terminal capabilities
setup_macos_terminal() {
# Enable color support
export TERM=xterm-256color
# Set up proper character encoding
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
# Optimize for macOS Terminal.app
if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]]; then
# Use Terminal.app specific features
echo -e "\033]0;Application Installer\007" # Set window title
fi
}
# macOS notification integration
send_notification() {
local title="$1"
local message="$2"
local sound="${3:-default}"
if command -v osascript >/dev/null 2>&1; then
osascript -e "display notification \"$message\" with title \"$title\" sound name \"$sound\""
fi
}