
1. 先把两个命令的身份说清楚如果你在 macOS 上装过开发环境brew install和brew cask install这两条命令大概率都敲过。前者装的是命令行工具后者装的是图形化应用这是最直白的区别但只停在这一层理解早晚会在某个具体场景里栽跟头——比如明明想装个编辑器用brew install死活找不到或者照着两年前的教程敲brew cask install终端直接甩你一脸报错。我自己的经历是这样的刚接触 Homebrew 那会儿看到教程里写brew install git又看到另一篇写brew cask install google-chrome当时的第一反应是cask 是不是一个更高级的开关。后来把 Homebrew 的目录结构翻了一遍才明白这俩压根不是同一个仓库体系里的东西甚至连装到哪里去都不一样。这篇内容我打算把这几件事讲透brew install和brew cask install在内核上到底差在哪为什么brew cask install这个写法现在会被警告甚至直接失败新版本里正确的替代命令是什么以及在国内网络环境下装 Homebrew、拉取软件包时那些让人头大的耗时问题该怎么缓解。不管你是刚装上 Homebrew 的新手还是用了两三年但一直抄命令不思考的老用户应该都能从里面找到点有用的东西。全文基于我这几台机器一台 M 系列芯片、一台老 Intel上的实测记录命令行为以 Homebrew 4.x 为准。2. 核心差异拆解Formula 与 Cask 是两套体系2.1 从安装目录反推两者的本质想快速理解区别最有效的办法不是看文档而是看装完之后文件落在哪。我在终端里做过一次对比# 装一个命令行工具 brew install jq # 查看它到底被放到了哪里 brew --prefix jq典型的输出是/opt/homebrew/Cellar/jq/1.7.1Apple Silicon或者/usr/local/Cellar/jq/1.7.1Intel。也就是说brew install装的软件最终会沉到 Homebrew 自己的酒窖目录里然后在/opt/homebrew/bin下建一个软链接让系统能在PATH里找到它。而 Cask 完全是另一条路子brew install --cask firefox装完之后你去/Applications目录看一眼Firefox.app 就老老实实躺在那儿跟手动拖进去的效果一模一样。Homebrew 在中间做的事情本质上是下载 dmg/zip/pkg挂载、解包、复制到应用程序目录然后留下一份元数据记录方便以后卸载和升级。这个差异直接决定了一个关键结论Cask 装的东西是给图形界面用的应用brew install装的东西是给终端用的工具。2.2 Formula 是什么一份从源码到二进制的配方Formula配方是 Homebrew 最原始的概念一个 formula 就是一个 Ruby 文件描述了这个东西怎么装。它通常包含这些信息软件名、版本号、主页地址源码 tarball 的下载地址和校验值sha256依赖列表depends_on编译参数configure args、构建步骤def install ... end测试方法test do ... endHomebrew 拿到这份配方之后有两条路线可走。第一条是自己编译下载源码、跑./configure make make install这条路慢但通用性强任何架构都能适配。第二条是直接下载别人预先编译好的二进制包也就是bottle。现在绝大多数常用软件都有官方 bottle所以brew install的实际体验是下载 解压 链接通常十几秒就完事而不是真的在你机器上编译半小时。提示判断一个包是走了 bottle 还是现场编译看安装日志里有没有出现Pouring这个词。出现Pouring就是直接倒二进制出现大段./configure输出就是真在本地编译。有一个细节值得单独说bottle 是按 macOS 版本和 CPU 架构分开构建的。比如你在 macOS 14 上跑 Apple SiliconHomebrew 会去找arm64_sonoma对应的 bottle。如果某个包没有适配你当前系统版本的 bottle它就会退回源码编译这时候耗时可能从十几秒变成十几分钟风扇狂转。我第一次在刚升级系统的大版本上装postgresql时就被这个坑过以为是网络慢其实是它默默在本地编译。2.3 Cask 是什么把手动下载安装这件事脚本化Cask 出现的动机特别朴素。因为 macOS 上大量好用的软件根本不通过命令行分发而是给你一个 dmg、一个 pkg 或者一个 zip。你手动装的时候是打开浏览器 → 找官网 → 下载 → 双击 → 拖进 Applications → 弹出确定要打开吗。Cask 把这一套流程写成了可复现的脚本。一个 cask 定义文件里通常包含url下载地址sha256文件校验值name、homepage名称与主页app、pkg、binary安装方式是复制 .app、安装 pkg还是链接一个可执行文件zap彻底卸载时要清理的残留目录列表这里有个很多教程不会提的点Cask 也能装命令行程序。有些工具官方只提供压缩包里面有可执行文件cask 可以通过binary指令把它链接到PATH里。反过来Formula 也能装 GUI 应用比如某些开源应用本身就提供 formula。所以命令行 vs 图形界面只是最常见的划分不是绝对规律。真正严谨的区分应该是formula 走的是 Homebrew 的构建/打包体系cask 走的是搬运现成发行包的体系。2.4 为什么非要分两套不合并成一套这个问题我在社区里看过不少讨论。答案其实不难理解两者的可验证性和依赖模型完全不同。Formula 的核心价值是可复现构建。给定配方和依赖理论上任何人都能构建出一致的结果还能做依赖图解析A 依赖 BB 依赖 C能做版本冲突检测。而 dmg 里的应用是个黑盒你没法声明这个 App 依赖某个库也没法保证它在不同系统版本上都能跑。它们唯一的共同点是下载和记录已安装状态其余全是差异。硬合并的后果就是依赖解析逻辑要为一堆黑盒应用做特例判断维护成本爆炸。所以 Homebrew 选择了统一入口、分别处理的路线——这也是理解后面命令演进的关键。3. 命令演进史cask 子命令为什么消失了3.1 早期brew cask 是独立项目很多人不知道Cask 最早根本不属于 Homebrew而是一个叫homebrew-cask的独立 Tap第三方仓库。所以早期的用法是两步brew tap caskroom/cask brew cask install google-chrome那时候brew cask是一个真正的子命令install是它的下级动作。命令结构和brew services start那种形式是一致的。3.2 中期合并进主仓库写成 brew cask install后来 Cask 被官方收编brew cask install xxx成了最流行的写法。那几年几乎所有中文教程都是这个格式你在网上搜mac 安装 xxx十篇里有八篇是brew cask install。问题在于Homebrew 后来开始反思这种命令设计。原因很实在brew install和brew cask install只差一个词新手经常搞混装错了还得卸载重来有些软件同时存在 formula 和 cask两个命令都能成功但装出来的东西不一样很容易出现我明明装过了怎么还是找不到命令的诡异情况维护两套参数解析逻辑代码冗余3.3 现在统一为 brew install --cask从 Homebrew 2.6.0 开始官方引入了--cask标志位到 2.7.0 之后brew cask install被标记为弃用再往后这个子命令形式基本被移除了。现在的正确写法是brew install --cask google-chrome如果你现在敲brew cask install google-chrome常见的结果是提示这个命令不存在或已被移除让你改用brew install --cask。所以凡是教程里还在写brew cask install的基本可以直接判定内容是两年前的跟着抄会遇到报错别慌不是你环境坏了。这里还有个小变化值得注意brew cask list、brew cask uninstall、brew cask upgrade这些也统统改了写法。对应的新形式我在下面整理成表方便对照。3.4 新旧写法对照速查功能旧写法已失效现在正确写法安装图形应用brew cask install xxxbrew install --cask xxx列出已装的 caskbrew cask listbrew list --cask卸载 caskbrew cask uninstall xxxbrew uninstall --cask xxx升级 caskbrew cask upgradebrew upgrade --cask搜索 caskbrew cask search xxxbrew search --cask xxx查看 cask 信息brew cask info xxxbrew info --cask xxx强制显式指定 formula无brew install --formula xxx这张表我建议直接存成笔记。因为中文技术社区里旧格式的内容存量极大搜索结果里新旧混杂没有这张对照表很容易被带偏。4. 一次安装到底发生了什么流程逐步拆解4.1 brew install 的完整链路我把一次brew install的过程拆成了六个阶段理解了这六步绝大部分报错你都能自己定位。第一阶段解析公式。Homebrew 先从本地仓库/opt/homebrew/Library/Taps/homebrew/homebrew-core里找对应的 formula 文件。找不到就更新索引还找不到就报No available formula。这也是为什么有时候要先跑brew update。第二阶段依赖计算。解析 formula 里的depends_on算出需要先装哪些东西。有意思的是Homebrew 会区分构建依赖和运行依赖构建依赖在装完之后不会被记录为运行时依赖。有些包依赖几十个上游库这一步会打印出一长串列表。第三阶段下载。按优先级找可用的 bottle拼出下载 URL拉取到缓存目录~/Library/Caches/Homebrew/downloads。这一步是耗时大头尤其在国内网络条件下。第四阶段校验。对下载文件算 sha256和 formula 里写死的值比对。不一致就报SHA256 mismatch。这个机制是为了防止下载过程中文件损坏或被替换。第五阶段解包并倒到 Cellar。bottle 解压后放到Cellar/包名/版本号目录。这一步的日志关键词是Pouring。第六阶段链接。在prefix/bin、prefix/lib下创建软链接指向 Cellar 里的实际文件。链接失败比如已有同名文件会提示Could not symlink。4.2 cask 安装流程的差异在哪Cask 的前两步基本一致解析 cask 定义、算依赖但从第三步开始分道扬镳下载的是 dmg、pkg 或 zip不是 bottle拿到 dmg 之后要hdiutil attach挂载从挂载卷里把 .app 复制到/Applications再hdiutil detach卸载pkg 类型则要调用系统安装器这一步通常需要管理员权限会弹窗要密码zip 类型直接解压后复制最后在/opt/homebrew/Caskroom/包名/版本号留下记录并写一份.metadata目录存放时间戳和版本信息所以你会观察到一个现象Cask 安装的软件不在brew --prefix目录里which也找不到它。想找它只能去/Applications或者用brew list --cask看列表。4.3 混乱地带同名 formula 与 cask这是最容易让人翻车的地方。举个典型例子有个开源软件同时提供了命令行版和图形版formula 名和 cask 名一样。这时候brew install xxx # 装的是命令行版 brew install --cask xxx # 装的是图形版两个都不会报错但装的是完全不同的东西。更坑的是如果你先装了 cask 版再brew install xxxHomebrew 可能会提示已安装让你误以为命令行工具也有了。遇到我装过了但没有这个命令的情况第一件事就是查清楚到底是 formula 还是 caskbrew info xxx # 看是不是 formula brew info --cask xxx # 看是不是 cask两个都查一遍心里就有数了。这个排查动作我用了很多次几乎每次都问题出在这儿。4.4 什么时候该主动指定 --formula--cask和--formula是一对互补的显式开关。日常用不到但在两种场景下很有价值一是写脚本或 CI 配置时。显式指定能避免 Homebrew 未来调整默认行为导致脚本失效。我的个人环境初始化脚本里所有安装命令都带了显式标志位。二是在同名冲突时强制走某条路线。有些包在某个版本之后默认行为变了显式指定能锁定你要的东西。注意--formula不是万能的。如果这个名字只有 cask 版本加了--formula会直接报错而不是回退到 cask。5. 网络慢、装得久这个问题的实际情况5.1 先判断慢在哪一环很多人一觉得慢就去换镜像源结果换完发现更慢了。根本原因是没定位到瓶颈。我的排查顺序是这样的# 看整体耗时分布 time brew install xxx # 看缓存目录里有哪些包哪些是刚下载的 ls -lht ~/Library/Caches/Homebrew/downloads | head -20 # 单独测一下更新索引这一步 time brew update一般来说慢的来源有三个brew update拉取仓库索引慢、下载 bottle 慢、下载 cask 里的 dmg 慢。三个环节走的是不同的域名解决方案也不一样。如果慢的是 dmg 下载换 Homebrew 镜像源一点用都没有因为 cask 里的下载地址指向的是软件官方服务器或 GitHub Release跟 Homebrew 自己的源没关系。这一点是我踩过最深的坑。当时装一个设计软件dmg 有 500MB换了镜像源后下载速度毫无变化后来才反应过来cask 的 url 字段写的是官方地址镜像源管不着。这种情况只能靠多试几次或者换个时间段实在不行就手动下载 dmg 再自己拖进去然后用brew list --cask确认状态。5.2 给 Homebrew 本体配镜像源如果你确定慢在索引更新或 bottle 下载配置镜像源是有明显效果的。以常用做法为例把下面这几行写进你的 shell 配置文件~/.zshrc或~/.bash_profile# Homebrew 加速相关环境变量 export HOMEBREW_API_DOMAINhttps://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/api export HOMEBREW_BOTTLE_DOMAINhttps://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles export HOMEBREW_BREW_GIT_REMOTEhttps://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git export HOMEBREW_CORE_GIT_REMOTEhttps://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git写完之后执行source ~/.zshrc让配置生效然后跑一次brew update验证。几个必须注意的点第一HOMEBREW_API_DOMAIN是较新版本 Homebrew 才认的变量。如果你的版本比较老这个变量会被忽略只能靠HOMEBREW_BOTTLE_DOMAIN起作用。用brew --version看一眼版本号4.x 以上基本都支持。第二镜像源和官方源不要在同一个会话里混用。有次我配置到一半环境变量只加了一半结果 git fetch 走官方、bottle 走镜像索引和实际包版本对不上报了奇怪的校验错误。后来清掉环境变量重来才好。所以要么全配要么不配。第三配完记得验证是否真的生效。加一个-v看下载地址brew install -v jq 21 | grep -i curl\|https输出里如果出现镜像站域名说明配置生效了。5.3 首次安装 Homebrew 本身的耗时预期新人最常问的一个问题是装 Homebrew 要多久。这个真没有标准答案我给出几种实测情况供参考场景大致耗时主要耗时环节网络条件良好直连官方源3 到 8 分钟拉取 brew 仓库与 core 仓库配置了镜像源2 到 5 分钟下载仓库压缩包与解压首次安装后跑 brew update1 到 3 分钟索引更新首次装一个带大量依赖的包3 到 20 分钟依赖链下载或退化为源码编译这里有个容易被忽略的隐藏选项Homebrew 官方安装脚本支持通过环境变量指定安装目录和仓库地址也就是NONINTERACTIVE和 git remote 相关的变量。对不想装到默认路径的人提前设好能省掉后面迁移的麻烦。提示安装脚本执行过程中如果中途断网不要重复从头跑。先看看/opt/homebrew或/usr/local/Homebrew目录是否已经存在残留目录可以直接复用执行brew update --force补齐即可。5.4 什么情况下不值得折腾镜像我不是无脑推荐所有人配镜像。有两种情况建议先别动一是你的网络到官方源本来就不慢装个jq十几秒搞定折腾镜像反而是给自己找麻烦因为镜像同步有延迟偶尔会遇到某个新版本 bottle 还没同步过来导致下载 404。二是你只是偶尔用一次 Homebrew装完就不怎么动了。这种情况下把配置写进 shell 文件反而增加了维护负担不如需要时临时export一下。6. 高频报错与排查路线6.1 报错速查表报错关键词大致原因处理方向No available formula名字写错或该包只有 cask 版本用brew search搜或换--caskNo Cask with this name exists该包只有 formula 版本去掉--cask重试SHA256 mismatch下载文件损坏或缓存脏了清理对应缓存重下Could not symlink目标路径已有同名文件按提示删掉冲突文件后brew linkis already installed but not linked装了但链接被破坏brew link --overwrite 包名refusing to installCask 安装 pkg 需要更高权限加上允许 pkg 参数或手动确认This command has been removed用了旧的brew cask install写法改写成brew install --caskdamaged and cant be opened应用带隔离属性视情况用xattr处理注意来源可信6.2 缓存的清理与善用Homebrew 的缓存目录会越攒越大我有次清理时发现占了快 8GB。相关命令# 查看缓存占用情况 du -sh ~/Library/Caches/Homebrew # 清理过期的下载缓存和旧版本 brew cleanup -s # 只看会清理什么不实际执行 brew cleanup -n-s参数是scrub会把所有缓存包括最新版的下载文件也删掉。日常用brew cleanup就够了它会保留需要的部分。这里有个实际经验遇到下载相关的诡异报错第一反应是清缓存重来成功率很高。因为缓存文件是按 URL 哈希命名的如果某次下载中途中断留下半个文件后续可能一直复用这个坏文件。这时候rm -rf ~/Library/Caches/Homebrew/downloads/对应文件 brew install xxx比盲目重试有效得多。6.3 架构相关的坑Apple Silicon 和 Intel 双架构并存这件事制造了一批不太好理解的报错。核心规则是Apple Silicon 原生 Homebrew 装在/opt/homebrew装 arm64 的包Intel 或 Rosetta 模式下装在/usr/local装 x86_64 的包如果你的终端跑在 Rosetta 下可以用arch命令看输出是arm64还是i386而你装的是原生 Homebrew就会遇到命令明明装了却找不到的问题——因为PATH指向的是另一套目录。这个问题我遇到过两次排查方法很简单which brew echo $PATH | tr : \n | grep -i homebrew arch三行命令下来问题基本就暴露了。解决方案就是统一要么让终端跑原生架构要么用对应架构的 Homebrew别混用。混用还有一个隐蔽后果装出来的 Cask 应用可能是 x86 版本性能差一截而且升级时行为不一致。6.4 关于隔离属性的一点说明用 Cask 装的应用首次打开时系统可能提示来源不明或已损坏。这在技术上是文件带了com.apple.quarantine扩展属性可以用xattr命令查看xattr -l /Applications/某个应用.app注意我不建议无脑批量清除隔离属性。这个机制本身是系统对下载文件的一道保护只有在确认安装包来源可信、且确实无法正常打开时才考虑针对性处理。把整台机器上所有应用的隔离属性一股脑清掉等于主动放弃一层防线。6.5 卸载的完整动作很多人以为brew uninstall就完事了其实 Cask 应用往往会留下配置和缓存。要干净卸载# 普通卸载 brew uninstall --cask 应用名 # 连同残留配置一起清理 brew uninstall --zap --cask 应用名--zap会读取 cask 定义里的zap列表把相关的偏好设置、缓存、日志目录一并删掉。我第一次用--zap的时候才发现某个应用在~/Library/Application Support下留了将近 2GB 的缓存普通卸载根本不动它。卸载后建议再跑一次检查brew list --cask | grep 应用名 brew doctorbrew doctor的输出虽然啰嗦但它确实能发现一些 PATH 顺序、权限、残留链接的问题。我一般只在遇到怪问题时才跑日常不用。7. 我自己的使用习惯和一些体会用了几年下来我形成了几个固定习惯分享出来供参考。第一个习惯安装前先brew info扫一眼。不要直接抄命令敲下去。brew info会告诉你这个包是否已安装、版本是多少、依赖有哪些、是不是 cask。花五秒钟省掉后面可能的十分钟排查。这个动作在装不熟悉的包时尤其值得。第二个习惯脚本里全部写显式标志位。我维护了一份个人环境初始化脚本所有命令都写成brew install --formula xxx或brew install --cask xxx。理由很简单Homebrew 的默认行为在版本演进中改过好几次显式写法能让脚本在几年后依然可用。这份脚本我隔一段时间在新机器上跑一次基本不用改。第三个习惯把brew update和brew upgrade分开执行。很多人习惯直接brew upgrade它内部会先更新索引。但分开执行的好处是索引更新失败时你能立刻看到而不是混在一大堆升级输出里被淹没。我通常每周跑一次brew update然后看情况决定升不升级——生产用的工具链不急着追新版本追新反而容易遇到刚发布版本的兼容问题。第四个习惯Cask 装的应用定期对一遍。因为 Cask 应用可以自己更新很多 App 内置了自动更新这就导致 Homebrew 记录的版本和实际版本不一致。这时候brew upgrade --cask可能出现已是最新但应用明明是新版的错位。遇到这种情况看 Caskroom 里的版本目录和实际 App 的版本号对比一下必要时重装一次让状态对齐。最后说一个关于命令选择的心得判断用brew install还是brew install --cask别去背分类用一句话判断就够了——你要的是敲命令用的东西还是双击图标打开的东西。前者走 formula后者走 cask。如果实在拿不准就两个brew info都查一遍哪边有结果用哪边两边都有结果说明这个软件确实提供了两种形态按需求挑。这个判断法我用了很久比记那些分类规则实用得多。