一键自动化部署 macOS 开发环境

【保姆级教程】一键自动化部署 macOS 开发环境(支持 Intel/Apple 芯片 & 自动避坑)

1. 背景

对于开发者来说,配置新 Mac 或重置开发环境是一项极其耗时的工作。Homebrew 的各种报错、环境变量的繁琐配置、以及 Docker 与系统组件的冲突往往让人头大。本文分享一个经过加固、兼容 macOS 全版本 Bash、且具备智能汇总报告的自动化脚本。


2. 脚本核心亮点

  • 极速安装:自动安装 Homebrew 及其核心开发组件。
  • 智能避坑:自动检测 Docker Desktop,防止与 Homebrew 版 Docker 冲突。
  • 静默安装:过滤 Homebrew 冗长的下载进度日志,只在屏幕展示关键进度。
  • 全版本兼容 :兼容 macOS 自带的 Bash 3.2,解决 declare -A 报错问题。
  • 可视化总结:执行完成后生成全组件安装状态汇总表。
  • 断点记录:自动记录所有操作到本地日志文件。

3. 环境要求

  • 系统版本:macOS 10.15 (Catalina) 及以上(支持最新的 macOS 15 Sequoia)。
  • 芯片架构:完美适配 Intel 芯片及 Apple Silicon (M1/M2/M3) 芯片。
  • 网络环境:建议能够正常访问 GitHub 或已配置镜像源。

4. 详细使用步骤

第一步:创建脚本文件

在终端执行以下命令,创建并编辑脚本:

bash 复制代码
nano install_dev_env.sh

将下面的脚本代码完整复制并粘贴进去。按下 Ctrl + O 保存,Ctrl + X 退出。

bash 复制代码
#!/bin/bash

# ==========================================
# macOS 开发环境安装脚本 (Bash 3.2 兼容版)
# ==========================================

# 基础设置
set -u
set -o pipefail

# --- 全局变量 ---
LOG_FILE="$HOME/.dev_env_install.log"
# 汇总报告的临时存储文件,替代关联数组
SUMMARY_FILE="/tmp/dev_env_summary.txt"
LOCK_FILE="/tmp/dev_env_install.lock"
BREW_PREFIX="" # 运行时探测
ARCH=""

# 颜色与格式
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m' # No Color

# 初始化汇总文件
: > "$SUMMARY_FILE"

# --- 辅助函数 ---

log_step() {
    echo -e "\n${BLUE}${BOLD}[STEP] $1${NC}"
    echo "[$(date '+%T')] [STEP] $1" >> "$LOG_FILE"
}

log_info() {
    echo -e "  ${CYAN}ℹ${NC} $1"
    echo "[$(date '+%T')] [INFO] $1" >> "$LOG_FILE"
}

log_success() {
    echo -e "  ${GREEN}✔${NC} $1"
    echo "[$(date '+%T')] [SUCCESS] $1" >> "$LOG_FILE"
}

log_warn() {
    echo -e "  ${YELLOW}⚠ $1${NC}"
    echo "[$(date '+%T')] [WARN] $1" >> "$LOG_FILE"
}

log_error() {
    echo -e "  ${RED}✖ $1${NC}"
    echo "[$(date '+%T')] [ERROR] $1" >> "$LOG_FILE"
}

# 记录状态到文件 (替代关联数组)
# 用法: record_status "组件名" "状态带颜色代码"
record_status() {
    echo "$1|$2" >> "$SUMMARY_FILE"
}

# 静默执行命令
run_silent() {
    local name="$1"
    local cmd="$2"
    
    echo -ne "  ${BOLD}➜${NC} 正在处理 $name ... "
    
    if eval "$cmd" >> "$LOG_FILE" 2>&1; then
        echo -e "\r  ${GREEN}✔${NC} $name 处理完成          "
        return 0
    else
        echo -e "\r  ${RED}✖${NC} $name 处理失败          "
        log_error "$name 执行出错,最后 10 行日志:"
        tail -n 10 "$LOG_FILE" | sed 's/^/    /'
        return 1
    fi
}

cleanup() {
    rm -f "$LOCK_FILE"
    # 不删除 SUMMARY_FILE 以便调试,或者你可以取消注释下一行
    # rm -f "$SUMMARY_FILE"
}
trap 'cleanup' EXIT

# --- 核心逻辑 ---

check_env() {
    log_step "环境预检"
    
    if [ -f "$LOCK_FILE" ]; then
        if ps -p "$(cat "$LOCK_FILE")" > /dev/null 2>&1; then
            log_error "脚本已在运行中 (PID: $(cat "$LOCK_FILE"))"
            exit 1
        fi
    fi
    echo $$ > "$LOCK_FILE"

    local ver=$(sw_vers -productVersion)
    # 兼容 Bash 3.2 的版本比较逻辑
    local ver_check=$(echo "$ver" | awk -F. '{ if ($1 > 10 || ($1 == 10 && $2 >= 15)) print "yes"; else print "no" }')
    
    if [[ "$ver_check" == "no" ]]; then
        log_error "macOS 版本过低 ($ver),需要 10.15+"
        exit 1
    fi
    log_info "系统版本: macOS $ver"

    local m_arch=$(uname -m)
    if [[ "$m_arch" == "arm64" ]]; then
        ARCH="arm"
        BREW_PREFIX="/opt/homebrew"
    else
        ARCH="intel"
        BREW_PREFIX="/usr/local"
    fi
    export PATH="$BREW_PREFIX/bin:$PATH"
    log_info "硬件架构: $ARCH ($BREW_PREFIX)"
}

install_homebrew() {
    log_step "Homebrew 设置"
    
    if command -v brew >/dev/null 2>&1; then
        log_success "Homebrew 已安装"
        run_silent "更新 Homebrew" "brew update"
    else
        log_info "正在安装 Homebrew..."
        # 注意:这里不能静默,因为 Homebrew 安装脚本可能需要用户输入密码
        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
        
        if [[ "$ARCH" == "arm" ]]; then
            eval "$($BREW_PREFIX/bin/brew shellenv)"
        fi
    fi
}

install_pkg() {
    local pkg_name="$1"
    local brew_name="$2"
    local cmd_check="$3"
    
    # 检查汇总文件是否已包含此组件(简单的重复检查)
    if grep -q "^${pkg_name}|" "$SUMMARY_FILE"; then
        return
    fi

    # 1. 检查命令
    if command -v "$cmd_check" >/dev/null 2>&1; then
        # 尝试获取版本号 (稍微复杂的 sed 适配不同输出)
        local raw_ver=$($cmd_check --version 2>&1 | head -n 1)
        # 简单的提取逻辑,避免复杂的 awk 报错
        record_status "$pkg_name" "${YELLOW}已安装 (本地)${NC}"
        log_info "$pkg_name 已存在,跳过安装"
        return
    fi

    # 2. 检查 Brew
    if brew list --formula | grep -q "^${brew_name}\$"; then
        record_status "$pkg_name" "${YELLOW}已安装 (Brew)${NC}"
        log_info "$pkg_name Brew Formula 已存在,跳过"
        return
    fi

    # 3. 安装
    if run_silent "安装 $pkg_name" "brew install $brew_name"; then
        record_status "$pkg_name" "${GREEN}安装成功${NC}"
    else
        record_status "$pkg_name" "${RED}安装失败${NC}"
    fi
}

handle_docker() {
    local pkg_name="Docker"
    
    if [ -d "/Applications/Docker.app" ]; then
        record_status "$pkg_name" "${YELLOW}已安装 (Desktop)${NC}"
        log_info "检测到 Docker Desktop,跳过"
        return
    fi

    if command -v docker >/dev/null 2>&1; then
        record_status "$pkg_name" "${YELLOW}已安装 (CLI)${NC}"
        return
    fi

    install_pkg "Docker" "docker" "docker"
}

process_components() {
    log_step "组件安装"

    # Bash 3.2 也不支持数组里放复杂字符串当结构体用,我们简单展开调用
    # 格式: 显示名称 Formula名称 检测命令
    
    install_pkg "Git"     "git"     "git"
    install_pkg "JDK"     "openjdk" "java"
    install_pkg "Maven"   "maven"   "mvn"
    install_pkg "Node.js" "node"    "node"
    install_pkg "Python"  "python"  "python3"
    install_pkg "MySQL"   "mysql"   "mysql"
    install_pkg "Redis"   "redis"   "redis-server"
    
    handle_docker
}

post_config() {
    log_step "后续配置"
    
    if brew list --formula | grep -q "openjdk"; then
        local jdk_home="$BREW_PREFIX/opt/openjdk/libexec/openjdk.jdk/Contents/Home"
        if ! grep -q "JAVA_HOME" "$HOME/.zshrc"; then
            echo "" >> "$HOME/.zshrc"
            echo "# Java Config" >> "$HOME/.zshrc"
            echo "export JAVA_HOME=\"$jdk_home\"" >> "$HOME/.zshrc"
            echo "export PATH=\"\$JAVA_HOME/bin:\$PATH\"" >> "$HOME/.zshrc"
            log_success "已配置 JAVA_HOME"
        else
            log_info "JAVA_HOME 已配置,跳过"
        fi
        
        if [ ! -d "/Library/Java/JavaVirtualMachines/openjdk.jdk" ]; then
            log_warn "建议手动执行以下命令修复 Java 路径识别:"
            echo "      sudo ln -sfn $BREW_PREFIX/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk"
        fi
    fi
}

print_summary() {
    echo -e "\n=========================================="
    echo -e "       🎉 安装结果汇总报告"
    echo -e "=========================================="
    printf "%-15s | %s\n" "组件名称" "状态"
    echo "------------------------------------------"
    
    # 从文件读取并格式化输出 (Bash 3.2 兼容写法)
    while IFS='|' read -r name status || [ -n "$name" ]; do
        if [ -n "$name" ]; then
            printf "%-15s | %b\n" "$name" "$status"
        fi
    done < "$SUMMARY_FILE"
    
    echo -e "=========================================="
    echo -e "详细日志: ${BOLD}$LOG_FILE${NC}"
    echo -e "请执行 ${BOLD}source ~/.zshrc${NC} 使配置生效。"
}

# --- 主程序 ---
main() {
    mkdir -p "$(dirname "$LOG_FILE")"
    echo "=== Session: $(date) ===" > "$LOG_FILE"
    
    check_env
    install_homebrew
    process_components
    post_config
    print_summary
}

main

第二步:授予执行权限

bash 复制代码
chmod +x install_dev_env.sh

第三步:一键运行

bash 复制代码
./install_dev_env.sh

脚本会引导你进行环境预检、安装 Homebrew、并逐一安装 Git、JDK、Node.js 等组件。

第四步:激活环境变量

安装完成后,终端会提示你:

bash 复制代码
source ~/.zshrc

5. 常见问题 (FAQ)

  • Q: 为什么 JDK 安装后系统识别不到?

  • A : 脚本会提示你执行一条 sudo ln -sfn... 命令。由于系统安全性限制,软链接需要手动确认。

  • Q: 安装过程中卡在 Homebrew 更新怎么办?

  • A : 脚本具备重试机制,如果网络极差,可以 Ctrl+C 中断后重新运行,脚本会自动跳过已安装的部分。


6. 环境还原 (卸载脚本)

如果你需要在一台机器上撤销所有操作(删除 Homebrew、清理环境变量、还原备份),请使用以下还原脚本。

还原脚本代码 (restore_env.sh)

bash 复制代码
#!/bin/bash

# ==========================================
# macOS 开发环境还原/卸载脚本
# ==========================================

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

echo -e "${RED}警告:此脚本将卸载通过脚本安装的组件并还原配置文件!${NC}"
read -p "确定要继续吗?(y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
    exit 1
fi

# 1. 还原配置文件
echo "正在从备份中还原配置文件..."
BACKUP_DIR="$HOME/.dev_env_backups"
if [ -d "$BACKUP_DIR" ]; then
    for cfg in .zshrc .bash_profile .bashrc; do
        latest_bak=$(ls -t "$BACKUP_DIR/$cfg.bak."* 2>/dev/null | head -n 1)
        if [ -n "$latest_bak" ]; then
            cp "$latest_bak" "$HOME/$cfg"
            echo -e "${GREEN}已还原 $cfg${NC}"
        fi
    done
fi

# 2. 卸载通过 Homebrew 安装的组件
if command -v brew >/dev/null 2>&1; then
    echo "正在卸载常用组件..."
    brew uninstall git openjdk maven node python mysql redis docker --force 2>/dev/null
fi

# 3. 询问是否卸载 Homebrew
read -p "是否彻底卸载 Homebrew?(y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    echo "正在卸载 Homebrew (可能需要输入密码)..."
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"
fi

# 4. 清理临时文件
rm -f /tmp/dev_env_install.lock /tmp/dev_env_summary.txt
echo -e "${GREEN}还原操作完成!请重启终端。${NC}"

还原脚本使用说明

  1. 创建文件:nano restore_env.sh 并粘贴上述代码。
  2. 授权:chmod +x restore_env.sh
  3. 执行:./restore_env.sh

7. 结语

通过自动化脚本,原本需要 1-2 小时的环境配置工作现在只需几分钟,且大大降低了手动配置出错的概率。如果你在 macOS 15.7.3 或其他版本上使用遇到问题,欢迎在评论区交流。


相关推荐
未来侦察班3 小时前
一晃13年过去了,苹果的Airdrop依然很坚挺。
macos·ios·苹果vision pro
七夜zippoe3 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
Fcy6484 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满4 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠5 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Harvey9035 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
珠海西格电力科技6 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
释怀不想释怀6 小时前
Linux环境变量
linux·运维·服务器
zzzsde6 小时前
【Linux】进程(4):进程优先级&&调度队列
linux·运维·服务器
普通网友8 小时前
苹果笔记本(Mac)连接手机完全指南
macos·智能手机