一键自动化部署 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 或其他版本上使用遇到问题,欢迎在评论区交流。


相关推荐
Bdygsl2 小时前
Linux(10)—— 进程控制(等待)
linux·运维·服务器
重生之绝世牛码2 小时前
Linux软件安装 —— Redis集群安装(三主三从)
大数据·linux·运维·数据库·redis·数据库开发·软件安装
renhongxia12 小时前
从文本到仿真:多智能体大型语言模型(LLM)自动化化学工艺设计工作流程
人工智能·语言模型·自动化
网硕互联的小客服2 小时前
如何彻底删除CentOS自带的postfix服务释放25端口?
linux·运维·centos
七七powerful2 小时前
docker 部署dirsearch并进行目录遍历扫描
运维·docker·容器
天码-行空2 小时前
CentOS 误删 /dev 目录救援方案
linux·运维·centos
小码吃趴菜2 小时前
mysql
linux·运维·服务器
呉師傅2 小时前
东芝3525AC彩色复印机打印配件寿命和打印错误记录方法【实际操作】
运维·服务器·网络·windows·电脑
霖霖总总2 小时前
[小技巧37]解构 my.cnf:[client] 与 [mysql] 背后的加载逻辑与优先级
运维·mysql