diff --git a/xu b/xu index 95d3248..af2b94c 100644 --- a/xu +++ b/xu @@ -8,7 +8,9 @@ set -e # 遇到错误立即退出 -@@ -12,6 +13,7 @@ GREEN='\033[0;32m' +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' @@ -16,7 +18,35 @@ CYAN='\033[0;36m' NC='\033[0m' # No Color # 自定义配置 -@@ -42,23 +44,60 @@ warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +PANEL_PORT="8443" +PANEL_USERNAME="3344" +PANEL_PASSWORD="3344" + +# 架构映射 +declare -A ARCH_MAP=( + ["x86_64"]="amd64" + ["amd64"]="amd64" + ["i386"]="386" + ["i686"]="386" + ["aarch64"]="arm64" + ["armv8l"]="arm64" + ["armv7l"]="armv7" + ["armv6l"]="armv6" + ["armv5l"]="armv5" + ["s390x"]="s390x" +) + +# GitHub Release URL +BASE_URL="https://github.com/vaxilu/x-ui/releases/latest/download" + +# 变量 +DETECTED_ARCH="" +DOWNLOAD_URL="" +DOWNLOAD_FILENAME="" + +# 日志函数 +info() { echo -e "${GREEN}[INFO]${NC} $1"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; } step() { echo -e "${BLUE}[STEP]${NC} $1"; } debug() { echo -e "${PURPLE}[DEBUG]${NC} $1"; } @@ -62,353 +92,336 @@ show_roar() { # 检测系统架构 detect_architecture() { -local arch=$(uname -m) - step "检测系统架构: $arch" + local arch=$(uname -m) step "🔍 正在检测系统架构..." cyan "👉 当前架构: $arch" -# 映射到对应的下载架构 -if [[ -n "${ARCH_MAP[$arch]}" ]]; then -DETECTED_ARCH="${ARCH_MAP[$arch]}" - info "检测到架构: $arch → $DETECTED_ARCH" + # 映射到对应的下载架构 + if [[ -n "${ARCH_MAP[$arch]}" ]]; then + DETECTED_ARCH="${ARCH_MAP[$arch]}" info "🎯 架构识别: $arch → $DETECTED_ARCH" -else - error "不支持的架构: $arch" + else error "❌ 不支持的架构: $arch" -echo - info "支持的架构:" - for key in "${!ARCH_MAP[@]}"; do - echo " $key -> ${ARCH_MAP[$key]}" - done + echo show_arch_info -exit 1 -fi + exit 1 + fi } -@@ -69,22 +108,23 @@ build_download_url() { -DOWNLOAD_URL="${BASE_URL}/${filename}" -DOWNLOAD_FILENAME="$filename" - info "下载文件: $DOWNLOAD_FILENAME" - debug "下载URL: $DOWNLOAD_URL" +# 构建下载URL +build_download_url() { + local filename="x-ui-linux-${DETECTED_ARCH}.tar.gz" + DOWNLOAD_URL="${BASE_URL}/${filename}" + DOWNLOAD_FILENAME="$filename" + info "📥 下载文件: $DOWNLOAD_FILENAME" debug "🔗 下载URL: $DOWNLOAD_URL" } # 检查 root 权限 check_root() { -if [ "$EUID" -ne 0 ]; then - error "请使用 root 权限运行此脚本" - info "尝试使用: sudo bash $0" + if [ "$EUID" -ne 0 ]; then error "❌ 请使用 root 权限运行此脚本!" info "💡 尝试使用: ${CYAN}sudo bash $0${NC}" -exit 1 -fi + exit 1 + fi info "✅ Root权限检查通过" } # 安装依赖 install_dependencies() { - info "检查并安装必要的依赖..." info "📦 检查并安装必要的依赖..." -if command -v apt-get >/dev/null 2>&1; then -# Debian/Ubuntu -@@ -100,44 +140,47 @@ install_dependencies() { -# Alpine -apk add wget tar curl sqlite -else - warn "无法确定包管理器,跳过依赖安装" + if command -v apt-get >/dev/null 2>&1; then + # Debian/Ubuntu + apt-get update + apt-get install -y wget tar curl sqlite3 + elif command -v yum >/dev/null 2>&1; then + # CentOS/RHEL + yum install -y wget tar curl sqlite + elif command -v dnf >/dev/null 2>&1; then + # Fedora + dnf install -y wget tar curl sqlite + elif command -v apk >/dev/null 2>&1; then + # Alpine + apk add wget tar curl sqlite + else warn "⚠ 无法确定包管理器,跳过依赖安装" -fi + fi info "✅ 依赖安装完成" } # 下载 x-ui download_xui() { - info "开始下载 x-ui..." info "📥 开始下载 x-ui..." -# 检查是否已存在文件 -if [ -f "$DOWNLOAD_FILENAME" ]; then - warn "发现已存在的文件 $DOWNLOAD_FILENAME" - read -p "是否重新下载? (y/N): " -n 1 -r + # 检查是否已存在文件 + if [ -f "$DOWNLOAD_FILENAME" ]; then warn "📁 发现已存在的文件: $DOWNLOAD_FILENAME" read -p "🔄 是否重新下载? (y/N): " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then -rm -f "$DOWNLOAD_FILENAME" -else - info "使用已存在的文件" + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -f "$DOWNLOAD_FILENAME" + else info "✅ 使用已存在的文件" -return 0 -fi -fi + return 0 + fi + fi -# 下载文件 - info "正在下载,请稍候..." + # 下载文件 info "⏬ 正在下载,请稍候..." cyan "💾 文件: $DOWNLOAD_FILENAME" -if wget --progress=bar:force "$DOWNLOAD_URL" -O "$DOWNLOAD_FILENAME"; then - info "下载完成" + if wget --progress=bar:force "$DOWNLOAD_URL" -O "$DOWNLOAD_FILENAME"; then info "✅ 下载完成!" -else - error "下载失败,请检查网络连接和URL" - error "URL: $DOWNLOAD_URL" + else error "❌ 下载失败!" error "🔗 请检查URL: $DOWNLOAD_URL" -exit 1 -fi + exit 1 + fi } # 解压并手动安装 extract_and_install() { - info "解压文件..." info "📂 解压文件..." -if [ ! -f "$DOWNLOAD_FILENAME" ]; then - error "文件 $DOWNLOAD_FILENAME 不存在" + if [ ! -f "$DOWNLOAD_FILENAME" ]; then error "❌ 文件 $DOWNLOAD_FILENAME 不存在" -exit 1 -fi + exit 1 + fi -@@ -146,8 +189,9 @@ extract_and_install() { -mkdir -p x-ui-temp + # 清理旧文件 + rm -rf x-ui-temp 2>/dev/null || true + mkdir -p x-ui-temp -# 解压文件 + # 解压文件 cyan "🔓 正在解压 $DOWNLOAD_FILENAME..." -if ! tar zxvf "$DOWNLOAD_FILENAME" -C x-ui-temp; then - error "解压失败,文件可能已损坏" + if ! tar zxvf "$DOWNLOAD_FILENAME" -C x-ui-temp; then error "❌ 解压失败,文件可能已损坏" -exit 1 -fi + exit 1 + fi -@@ -159,11 +203,11 @@ extract_and_install() { -cd x-ui -fi + # 进入解压目录 + if [ -d "x-ui-temp/x-ui" ]; then + cd x-ui-temp/x-ui + else + cd x-ui-temp + fi - info "开始手动安装 x-ui..." info "🔧 开始手动安装 x-ui..." -# 检查必要的文件 -if [ ! -f "x-ui" ]; then - error "未找到 x-ui 可执行文件" + # 检查必要的文件 + if [ ! -f "x-ui" ]; then error "❌ 未找到 x-ui 可执行文件" -ls -la -exit 1 -fi -@@ -175,7 +219,7 @@ extract_and_install() { -fi + ls -la + exit 1 + fi -# 手动安装 - info "执行手动安装..." + # 检查 sqlite3 数据库文件 + if [ ! -f "x-ui.db" ]; then + # 如果压缩包里没有数据库文件,我们会稍后创建 + warn "⚠ 未找到数据库文件,将使用默认配置" + fi + + # 手动安装 info "⚡ 执行手动安装..." -# 停止可能存在的旧服务 -systemctl stop x-ui 2>/dev/null || true -@@ -211,11 +255,12 @@ extract_and_install() { + # 停止可能存在的旧服务 + systemctl stop x-ui 2>/dev/null || true -# 返回原目录 -cd - > /dev/null + # 创建目录 + mkdir -p /etc/x-ui + mkdir -p /usr/local/x-ui + + # 复制文件 + cp -f x-ui /usr/local/x-ui/ + chmod +x /usr/local/x-ui/x-ui + + # 复制数据库文件(如果存在) + if [ -f "x-ui.db" ]; then + cp -f x-ui.db /etc/x-ui/ + fi + + # 创建软链接 + ln -sf /usr/local/x-ui/x-ui /usr/local/bin/x-ui + + # 返回原目录 + cd - > /dev/null info "✅ 文件安装完成" } # 配置系统服务 setup_service() { - info "配置系统服务..." info "🔌 配置系统服务..." -# 如果服务文件不存在,创建它 -if [ ! -f "/etc/systemd/system/x-ui.service" ]; then -@@ -236,19 +281,20 @@ RestartSec=5s + # 如果服务文件不存在,创建它 + if [ ! -f "/etc/systemd/system/x-ui.service" ]; then + cat > /etc/systemd/system/x-ui.service << EOF +[Unit] +Description=x-ui Service +After=network.target +Wants=network.target + +[Service] +Type=simple +WorkingDirectory=/usr/local/x-ui +ExecStart=/usr/local/x-ui/x-ui +Restart=on-failure +RestartSec=5s + [Install] WantedBy=multi-user.target EOF - info "创建了 systemd 服务文件" info "📄 创建了 systemd 服务文件" -fi + fi -systemctl daemon-reload -systemctl enable x-ui + systemctl daemon-reload + systemctl enable x-ui info "✅ 系统服务配置完成" } # 自定义配置面板 customize_panel() { - step "开始自定义配置面板..." step "🎛️ 开始自定义配置面板..." -# 停止服务以进行配置 - info "停止 x-ui 服务进行配置..." + # 停止服务以进行配置 info "🛑 停止 x-ui 服务进行配置..." -systemctl stop x-ui 2>/dev/null || true + systemctl stop x-ui 2>/dev/null || true -# 等待服务停止 -@@ -259,82 +305,77 @@ customize_panel() { + # 等待服务停止 + sleep 3 -# 初始化数据库(如果不存在) -if [ ! -f "/etc/x-ui/x-ui.db" ]; then - info "初始化数据库..." + # 确保目录存在 + mkdir -p /etc/x-ui + + # 初始化数据库(如果不存在) + if [ ! -f "/etc/x-ui/x-ui.db" ]; then info "🗃️ 初始化数据库..." -# 启动服务以创建初始数据库 -if systemctl start x-ui; then -sleep 5 -systemctl stop x-ui -sleep 3 -else - warn "服务启动失败,尝试直接创建数据库结构" - # 这里可以添加直接创建数据库的逻辑 - fi - - if [ ! -f "/etc/x-ui/x-ui.db" ]; then - warn "无法自动创建数据库文件,将在首次启动时创建" - return 0 + # 启动服务以创建初始数据库 + if systemctl start x-ui; then + sleep 5 + systemctl stop x-ui + sleep 3 + else warn "⚠ 服务启动失败,尝试直接创建数据库结构" -fi -fi + fi + fi -# 修改配置(如果数据库存在且可写) -if [ -f "/etc/x-ui/x-ui.db" ] && command -v sqlite3 >/dev/null 2>&1; then - info "设置面板端口为: $PANEL_PORT" + # 修改配置(如果数据库存在且可写) + if [ -f "/etc/x-ui/x-ui.db" ] && command -v sqlite3 >/dev/null 2>&1; then cyan "🔧 设置面板端口: $PANEL_PORT" -sqlite3 /etc/x-ui/x-ui.db "UPDATE setting SET value = '$PANEL_PORT' WHERE key = 'port';" 2>/dev/null || true + sqlite3 /etc/x-ui/x-ui.db "UPDATE setting SET value = '$PANEL_PORT' WHERE key = 'port';" 2>/dev/null || true - info "设置面板账号: $PANEL_USERNAME, 密码: $PANEL_PASSWORD" cyan "👤 设置面板账号: $PANEL_USERNAME" cyan "🔑 设置面板密码: $PANEL_PASSWORD" -sqlite3 /etc/x-ui/x-ui.db "UPDATE users SET username = '$PANEL_USERNAME', password = '$PANEL_PASSWORD' WHERE id = 1;" 2>/dev/null || true + sqlite3 /etc/x-ui/x-ui.db "UPDATE users SET username = '$PANEL_USERNAME', password = '$PANEL_PASSWORD' WHERE id = 1;" 2>/dev/null || true -sqlite3 /etc/x-ui/x-ui.db "UPDATE setting SET value = 'false' WHERE key = 'hasDefaultCredential';" 2>/dev/null || true - info "自定义配置完成" + sqlite3 /etc/x-ui/x-ui.db "UPDATE setting SET value = 'false' WHERE key = 'hasDefaultCredential';" 2>/dev/null || true info "✅ 自定义配置完成" -else - warn "无法自动配置数据库,请在安装后手动修改配置" + else warn "⚠ 无法自动配置数据库,请在安装后手动修改配置" -fi + fi } # 配置防火墙 setup_firewall() { - info "配置防火墙..." info "🔥 配置防火墙..." -# 检查防火墙状态 -if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "active"; then -# ufw -ufw allow ${PANEL_PORT}/tcp comment "x-ui Panel" -ufw allow 10000-20000/tcp comment "x-ui Proxy Ports" - info "UFW 防火墙已配置" + # 检查防火墙状态 + if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "active"; then + # ufw + ufw allow ${PANEL_PORT}/tcp comment "x-ui Panel" + ufw allow 10000-20000/tcp comment "x-ui Proxy Ports" info "✅ UFW 防火墙已配置" -elif command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then -# firewalld -firewall-cmd --permanent --add-port=${PANEL_PORT}/tcp -firewall-cmd --permanent --add-port=10000-20000/tcp -firewall-cmd --reload - info "Firewalld 防火墙已配置" + elif command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then + # firewalld + firewall-cmd --permanent --add-port=${PANEL_PORT}/tcp + firewall-cmd --permanent --add-port=10000-20000/tcp + firewall-cmd --reload info "✅ Firewalld 防火墙已配置" -elif command -v iptables >/dev/null 2>&1; then -# iptables -iptables -I INPUT -p tcp --dport ${PANEL_PORT} -j ACCEPT -iptables -I INPUT -p tcp --dport 10000:20000 -j ACCEPT - info "iptables 规则已添加" + elif command -v iptables >/dev/null 2>&1; then + # iptables + iptables -I INPUT -p tcp --dport ${PANEL_PORT} -j ACCEPT + iptables -I INPUT -p tcp --dport 10000:20000 -j ACCEPT info "✅ iptables 规则已添加" -# 尝试保存 iptables 规则 -if command -v iptables-save >/dev/null 2>&1; then -iptables-save > /etc/iptables.rules 2>/dev/null || true -fi -else - warn "未检测到防火墙,跳过配置" + # 尝试保存 iptables 规则 + if command -v iptables-save >/dev/null 2>&1; then + iptables-save > /etc/iptables.rules 2>/dev/null || true + fi + else warn "⚠ 未检测到防火墙,跳过配置" -fi + fi } # 启动服务 start_service() { - info "启动 x-ui 服务..." info "🚀 启动 x-ui 服务..." -systemctl daemon-reload -systemctl enable x-ui + systemctl daemon-reload + systemctl enable x-ui -# 启动服务 -if systemctl start x-ui; then - info "x-ui 服务启动命令执行成功" + # 启动服务 + if systemctl start x-ui; then info "✅ x-ui 服务启动命令执行成功" -else - error "x-ui 服务启动失败" + else error "❌ x-ui 服务启动失败" -return 1 -fi + return 1 + fi -@@ -343,25 +384,25 @@ start_service() { + # 等待服务启动 + sleep 3 -# 检查服务状态 -if systemctl is-active --quiet x-ui; then - info "✓ x-ui 服务运行正常" + # 检查服务状态 + if systemctl is-active --quiet x-ui; then info "✅ x-ui 服务运行正常" -# 显示服务状态 -echo -systemctl status x-ui --no-pager -l -else -warn "⚠ x-ui 服务未运行,检查日志中..." -systemctl status x-ui --no-pager -l - warn "尝试手动启动: systemctl start x-ui" + # 显示服务状态 + echo + systemctl status x-ui --no-pager -l + else + warn "⚠ x-ui 服务未运行,检查日志中..." + systemctl status x-ui --no-pager -l warn "💡 尝试手动启动: systemctl start x-ui" -fi + fi } # 验证安装 verify_installation() { - step "验证安装..." step "🔍 验证安装..." -# 检查服务状态 -if systemctl is-active --quiet x-ui; then - info "✓ 服务运行正常" + # 检查服务状态 + if systemctl is-active --quiet x-ui; then info "✅ 服务运行正常" -else -warn "⚠ 服务未运行,但安装已完成" -return 0 -@@ -370,19 +411,19 @@ verify_installation() { -# 检查端口监听 -if command -v netstat >/dev/null 2>&1; then -if netstat -tunlp 2>/dev/null | grep -q ":${PANEL_PORT} "; then - info "✓ 端口 ${PANEL_PORT} 监听正常" - info "✅ 端口 ${PANEL_PORT} 监听正常" -else -warn "⚠ 端口 ${PANEL_PORT} 未监听" -fi -elif command -v ss >/dev/null 2>&1; then -if ss -tunlp 2>/dev/null | grep -q ":${PANEL_PORT} "; then - info "✓ 端口 ${PANEL_PORT} 监听正常" - info "✅ 端口 ${PANEL_PORT} 监听正常" -else -warn "⚠ 端口 ${PANEL_PORT} 未监听" -fi -fi + else + warn "⚠ 服务未运行,但安装已完成" + return 0 + fi + + # 检查端口监听 + if command -v netstat >/dev/null 2>&1; then + if netstat -tunlp 2>/dev/null | grep -q ":${PANEL_PORT} "; then + info "✅ 端口 ${PANEL_PORT} 监听正常" + else + warn "⚠ 端口 ${PANEL_PORT} 未监听" + fi + elif command -v ss >/dev/null 2>&1; then + if ss -tunlp 2>/dev/null | grep -q ":${PANEL_PORT} "; then + info "✅ 端口 ${PANEL_PORT} 监听正常" + else + warn "⚠ 端口 ${PANEL_PORT} 未监听" + fi + fi - info "验证完成" info "✅ 验证完成" } # 显示安装信息 -@@ -391,54 +432,67 @@ show_info() { -local server_ip=$(curl -s --connect-timeout 5 ipv4.icanhazip.com || hostname -I | awk '{print $1}' || echo "你的服务器IP") +show_info() { + local server_ip=$(curl -s --connect-timeout 5 ipv4.icanhazip.com || hostname -I | awk '{print $1}' || echo "你的服务器IP") -echo - info "==================================================" - info "🎉 x-ui 多架构安装完成!" - info "==================================================" - info "系统架构: $(uname -m) → $DETECTED_ARCH" - info "管理面板: http://${server_ip}:${PANEL_PORT}" - info "用户名: $PANEL_USERNAME" - info "密码: $PANEL_PASSWORD" - info "" - info "面板状态: 已自动配置为指定端口和账号" - info "" + echo echo -e "${GREEN}╔══════════════════════════════════════════════════╗" echo -e "║ ║" echo -e "║ 🎉 X-UI 多架构安装完成!咸v咆哮牛逼! ║" @@ -422,20 +435,10 @@ echo echo cyan "💡 面板状态: 已自动配置为指定端口和账号" echo -warn "⚠️ 重要安全提醒:" -warn "1. 请立即访问面板验证登录" + warn "⚠️ 重要安全提醒:" + warn "1. 请立即访问面板验证登录" warn "2. 建议定期修改密码" - warn "2. 建议定期修改密码" -warn "3. 确保防火墙已正确配置" - info "" - info "常用命令:" - info "启动服务: systemctl start x-ui" - info "停止服务: systemctl stop x-ui" - info "重启服务: systemctl restart x-ui" - info "查看状态: systemctl status x-ui" - info "查看日志: journalctl -u x-ui -f" - info "管理菜单: x-ui" - info "==================================================" + warn "3. 确保防火墙已正确配置" echo info "🔧 常用命令:" info " 启动服务: systemctl start x-ui" @@ -444,18 +447,15 @@ warn "3. 确保防火墙已正确配置" info " 查看状态: systemctl status x-ui" info " 查看日志: journalctl -u x-ui -f" info " 管理菜单: x-ui" -echo - -# 显示访问URL - step "立即访问: http://${server_ip}:${PANEL_PORT}" - step "使用账号: $PANEL_USERNAME 密码: $PANEL_PASSWORD" echo + + # 显示访问URL echo -e "${CYAN}" echo "╔══════════════════════════════════════════════════╗" echo "║ 🚀 立即访问 🚀 ║" echo "║ ║" echo "║ http://${server_ip}:${PANEL_PORT} ║" - echo "║ ║" + echo "║ ║" echo "║ 👤 账号: $PANEL_USERNAME ║" echo "║ 🔑 密码: $PANEL_PASSWORD ║" echo "║ ║" @@ -465,15 +465,8 @@ echo # 显示架构信息 show_arch_info() { -echo -info "🖥️ 支持的架构列表:" - echo " x86_64 - 64位 Intel/AMD 处理器 → amd64" - echo " i386 - 32位 Intel/AMD 处理器 → 386" - echo " aarch64 - 64位 ARM 处理器 → arm64" - echo " armv7l - 32位 ARM v7 → armv7" - echo " armv6l - 32位 ARM v6 → armv6" - echo " armv5l - 32位 ARM v5 → armv5" - echo " s390x - IBM 大型机 → s390x" + echo + info "🖥️ 支持的架构列表:" echo -e " ${CYAN}x86_64${NC} - 64位 Intel/AMD 处理器 ${GREEN}→ amd64${NC}" echo -e " ${CYAN}i386${NC} - 32位 Intel/AMD 处理器 ${GREEN}→ 386${NC}" echo -e " ${CYAN}aarch64${NC} - 64位 ARM 处理器 ${GREEN}→ arm64${NC}" @@ -481,24 +474,31 @@ info "🖥️ 支持的架构列表:" echo -e " ${CYAN}armv6l${NC} - 32位 ARM v6 ${GREEN}→ armv6${NC}" echo -e " ${CYAN}armv5l${NC} - 32位 ARM v5 ${GREEN}→ armv5${NC}" echo -e " ${CYAN}s390x${NC} - IBM 大型机 ${GREEN}→ s390x${NC}" -echo + echo } # 主函数 main() { - info "开始 x-ui 多架构自动安装..." show_banner show_roar info "🚀 开始 x-ui 多架构自动安装..." -show_arch_info + show_arch_info -# 执行安装步骤 -@@ -455,19 +509,26 @@ main() { -verify_installation -show_info + # 执行安装步骤 + check_root + detect_architecture + build_download_url + install_dependencies + download_xui + extract_and_install + setup_service + customize_panel + setup_firewall + start_service + verify_installation + show_info - info "安装脚本执行完毕" echo echo -e "${RED}╔════════════════════════════════════════╗" echo -e "║ ║" @@ -512,16 +512,15 @@ show_info # 显示欢迎信息 show_banner echo -warn "🚀 x-ui 多架构自动安装脚本" -info "默认配置: 端口 ${PANEL_PORT} | 账号 ${PANEL_USERNAME}/${PANEL_PASSWORD}" cyan "🔧 默认配置: 端口 ${PANEL_PORT} | 账号 ${PANEL_USERNAME} | 密码 ${PANEL_PASSWORD}" echo -read -p "是否继续安装? (y/N): " -n 1 -r read -p "🔥 是否开始安装? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then - info "安装已取消" info "👋 安装已取消" -exit 0 + exit 0 fi + +# 执行主函数 +main