rea 这个命令我在本地开发机、内网服务器、还有几个 CI 容器镜像里都装过,前后折腾了七八次,curl 脚本和 npm 全局安装这两条路都走过,也都在上面栽过跟头。最惨的一次是在一台没有外网直连的机器上,用 npm 装完显示成功,敲rea --version直接报“找不到命令”,排查了四十分钟才定位到是全局 bin 目录压根没进 PATH;还有一次更冤,两条路各装了一遍,结果机器上同时躺着两份不同版本的 rea,跑出来的结果对不上,日志看了半天才发现调用的不是同一个二进制。所以这篇不打算写成“官方安装文档的搬运”,而是把这两种安装方式拆到骨头上讲清楚:它们各自在文件系统里动了什么、为什么会有这种差异、什么样的机器该选哪条路、装完跑不起来的时候按什么顺序排查。如果你刚接触这个命令行工具,或者被“装是装上了但就是用不了”折磨过,下面这些内容基本能覆盖你 90% 的场景;如果你已经能熟练安装,那么第 4 节的横向对比表和第 5 节的排查链路,应该还能帮你省下几次重复劳动。
1. 装 rea 之前先想清楚:你到底在装什么
1.1 一条安装命令背后其实是四样东西
很多人把“安装 rea 命令”理解成“把一个文件放到某个地方”,这个理解只对了一半。真正落地到磁盘上,一次完整的安装至少要处理四件事,任何一件没做对,都会表现为“命令找不到”或者“命令能跑但行为异常”。
第一是可执行本体。它可能是编译好的平台相关二进制文件,也可能是打包过的 JS 入口脚本。前者绑定 CPU 架构和运行时库,比如 x86_64 与 arm64 是两个完全不同的产物,glibc 环境和 musl 环境(常见于精简容器镜像)也不能混用;后者则依赖机器上已经存在 Node.js 解释器。
第二是依赖。curl 脚本分发的方式,通常会把运行时依赖一起打进产物里做成自包含形态,装完就是一个目录或一个文件,拷走就能用。npm 分发的方式则把依赖写成node_modules依赖树,装的时候要按package.json把一堆包拉下来。
第三是落盘位置。这决定了系统能不能找到这个命令。常见的落点是/usr/local/bin、~/.local/bin、~/.npm-global/bin,Windows 上则是%APPDATA%\npm这类目录。命令本身在不在,和它在不在 PATH 里,这是两个独立的问题,后面第 5 节会专门讲这个坑。
第四是配置与缓存目录。绝大多数 CLI 工具第一次运行时会创建自己的配置目录,比如~/.config/rea或者~/.rea,里面存版本信息、缓存、凭证之类的东西。这个目录在卸载时经常被忽略,这也是“重装之后行为还是不对”的常见原因。
提示:动手之前先跑一遍
type -a rea(Windows 用where rea)。如果已经有输出,说明机器上可能已经装过,先搞清楚旧版本在哪儿,再决定是覆盖还是清理,能避免八成的版本冲突问题。
1.2 两种安装方式的本质差异在哪里
把这两条路抽象一下,差异其实非常清晰:curl 脚本是一条“专用安装通道”,npm 全局安装是一条“通用包管理通道”。
curl 脚本本质上是一个安装器程序,它自己负责识别操作系统和架构、自己拼出下载地址、自己解压、自己往 PATH 里塞软链、自己打印后续操作提示。优点是对环境几乎没有前置要求,只要机器上有 curl 或者 wget 就能开工,装出来的东西也通常是一个干净的自包含目录;缺点是它是一段你不完全了解的代码,而且每个项目的安装脚本实现风格都不一样,出错时的报错信息质量参差不齐。
npm 全局安装走的是包管理器,下载、解压、依赖解析、bin 软链这些事都由 npm 统一处理,你享受到的是成熟工具链带来的可复现性和审计能力——npm ls -g --depth=0能看到装了什么版本,npm view rea versions能列出所有可装版本,卸载也是标准化的一条命令。代价是你得先有 Node.js 环境,而且很多 CLI 包的 npm 版本只是个“壳”,真正的二进制文件是在postinstall阶段另外下载的,这一步失败率不低。
1.3 三分钟选型表
先给结论,下面的表格是我自己实际选择时用的判断依据,细节解释放在后面几节。
| 判断维度 | curl 脚本安装 | npm 全局安装 |
|---|---|---|
| 前置依赖 | 只需 curl 或 wget | 需要 Node.js 与 npm,且版本要达标 |
| 产物形态 | 自包含目录或单文件 | 包目录 + 依赖树 + bin 软链 |
| 默认落点 | 脚本内定,通常是/usr/local/bin或用户目录 | npm 的全局 prefix 下的bin |
| 权限要求 | 写到系统目录时需要提权 | 写到系统 prefix 时需要提权 |
| 版本指定 | 靠环境变量,看脚本是否支持 | 原生支持rea@1.4.2 |
| 升级方式 | 重跑脚本 | npm i -g rea@latest |
| 卸载干净度 | 取决于脚本是否提供卸载入口 | 一条命令,但缓存目录要自己清 |
| 离线安装 | 把产物带过去即可 | 需要离线包或私有包源 |
| 多版本共存 | 改安装目录即可 | 需要切 prefix 或借用版本管理器 |
一句话概括我的习惯:临时用、内网机器、容器镜像、没有 Node 环境的场景走 curl;本来就跑 Node 的开发机、需要锁版本复现的 CI、需要频繁切版本的场景走 npm。这个判断在后面第 4 节还会展开。
2. curl 脚本安装:一行命令背后的全部动作
2.1 安装脚本通常会做的五件事
虽然各家项目的安装脚本写法不同,但结构上高度相似,基本都跑不出这五步:检测平台与架构、拼出对应产物的下载地址、下载并校验、解压到目标目录、把可执行文件链接到 PATH 里的某个目录。有的脚本还会多一步,检查系统里是否已有旧版本并提示覆盖。
理解这五步的实际价值在于:当安装失败时,你能立刻判断是卡在哪一步。比如报错说“不支持的平台”,那是第一步的架构识别没匹配上;报错说sha256 mismatch,那是第三步的校验没过,通常是下载被截断或者拿到了一个错误页面的 HTML;装完提示成功但命令不能用,那基本是第五步的 PATH 没生效。
以检测平台这一步为例,脚本内部一般会跑类似uname -s和uname -m的组合判断。uname -m输出x86_64就对应 amd64 产物,输出aarch64或arm64就对应 arm64 产物。容器镜像里这一步特别容易翻车:在一台 arm 架构的机器上跑 amd64 的镜像,uname -m可能报出x86_64,脚本于是下载了 amd64 二进制,结果一执行就报exec format error。遇到这个报错别急着怀疑安装脚本,先确认uname -m和你以为的是不是一回事。
2.2 先下载再执行,别图省事直接管道
网上流传最多的写法是curl -fsSL <地址> | bash。这个写法确实方便,但我强烈建议你至少在第一次安装、或者在一台重要机器上安装时,改成两步走:先落到本地文件,看完再执行。
# 第一步:把安装脚本下载到本地,不执行 curl -fsSL https://install.example.com/rea/install.sh -o rea-install.sh # 第二步:审阅内容 less rea-install.sh # 第三步:确认没问题再执行 bash rea-install.shcurl后面那几个参数值得记住:-f表示 HTTP 状态码异常时直接失败,不加这个参数的话,服务器返回一个 404 页面也会被当成脚本内容存下来,然后你执行的就是一堆 HTML;-s是静默模式,不打印进度条;-S是在静默模式下仍然输出错误信息,这两个通常一起用;-L是跟随重定向,缺了它遇到跳转就只拿到一个空文件。
审阅的时候重点看几个地方:脚本里出现的所有下载地址是不是你预期的域名;有没有sudo、rm -rf、修改 shell 配置文件的动作;写入的目录是不是你能接受的。如果你只是想在当前用户下用,不希望脚本去动/usr/local/bin,那就得看它支不支持自定义目录。
2.3 指定版本、指定安装目录的实操
大部分正经的安装脚本都会支持通过环境变量覆盖默认行为,最常见的两个是版本号和安装根目录。变量名各家不一样,一般会在脚本开头的注释或者官方文档里写明,下面用常见的命名方式举例:
# 指定版本 + 指定安装到用户目录,避免动系统目录 REA_VERSION=1.4.2 \ REA_HOME="$HOME/.local/share/rea" \ bash rea-install.sh# 安装完成后手动确认产物落点 ls -la "$HOME/.local/share/rea" find "$HOME/.local/share/rea" -maxdepth 2 -type f -name 'rea*'如果你不确定脚本支持哪些变量,有个笨但有效的办法:grep -n 'REA_' rea-install.sh把所有相关变量名捞出来看一眼,再结合grep -n '\${' rea-install.sh看它读了哪些环境变量。比盲猜快得多。
安装到用户目录有个额外好处:不需要 sudo,卸载时直接删目录,也不会污染系统路径。代价是你得自己确保那个目录下的bin进了 PATH,这一点在第 2.6 小节展开。
2.4 校验这一步别跳过
下载类安装最容易出问题的地方就是“下载到的不是你以为的东西”。可能是网络中断导致文件被截断,也可能是某层缓存返回了一个错误页面,还可能是在不可信的网络环境下被替换。正经的安装脚本会内置哈希校验,但如果你手动下载产物,就得自己校验。
# 计算实际哈希 sha256sum rea_1.4.2_linux_amd64.tar.gz # 与官方公布的值比对,或与随包提供的校验文件比对 sha256sum -c rea_1.4.2_checksums.txt # 如果项目提供签名,进一步验证 # 具体命令取决于签名方案,以官方文档为准macOS 上把sha256sum换成shasum -a 256。Windows 的 PowerShell 里用Get-FileHash -Algorithm SHA256。这些命令的输出格式略有差异,但比对逻辑一样:把算出来的值和官方公布的值逐字符对一遍,别看个大概。
注意:如果安装脚本里带
curl | bash这种自我执行的写法,而你又是在生产机器或者有敏感数据的机器上操作,务必先下载审阅。这不是多余的谨慎,安装脚本的权限等同于你自己敲的命令。
2.5 权限:别用 sudo 跑整个脚本
一个很常见的坏习惯是sudo bash rea-install.sh。这么做的后果是脚本创建的所有文件、目录、软链的属主都变成了 root,后续你用普通用户跑rea时,一旦它需要写缓存目录就会报权限错误,而且这个错误信息通常长得很不像权限问题,排查起来相当费劲。
更合理的做法是让脚本以普通用户身份运行,只在最后需要往系统目录写软链时用一次 sudo:
# 普通用户身份安装到用户目录 REA_HOME="$HOME/.local/share/rea" bash rea-install.sh # 只在这一步提权,把可执行文件链到系统 bin sudo ln -sf "$HOME/.local/share/rea/bin/rea" /usr/local/bin/rea # 确认软链指向正确 ls -l /usr/local/bin/rea如果你连这一步都不想提权,那就老老实实把~/.local/bin加进 PATH,全程不需要任何特权。这个方案在多用户共享的机器上尤其合适,每个人装自己的,互不干扰。
2.6 装完了命令还是找不到:PATH 生效的正确姿势
这是 curl 方式安装后最高频的问题。脚本往~/.bashrc或者~/.zshrc里追加了一行export PATH=...,但当前这个终端窗口是读不到新配置的,因为 shell 启动时才读一次配置文件。
# 确认配置文件里确实写进去了 tail -n 5 ~/.bashrc tail -n 5 ~/.zshrc # 让当前窗口立即生效 source ~/.bashrc # 如果之前敲过一次命令,shell 可能缓存了"命令不存在",清一下缓存 hash -r # 再验证 type -a rea rea --versionhash -r这一步很多人不知道。bash 会缓存命令路径查找结果,如果你在 PATH 修好之前敲过一次rea,它会记住“这个命令不存在”,修好 PATH 后仍然报错,看起来像是没生效。type -a rea比which rea更好用,因为它会把所有同名命令都列出来,能第一时间发现机器上有几份。
2.7 内网与离线场景怎么处理
完全没有外网的机器上,curl 脚本这条路反而更省事:在有网的机器上下载好对应架构的产物压缩包和校验文件,拷到目标机器,解压到目录,加 PATH,三步就完了,全程不需要任何包管理器。
# 目标机器上 mkdir -p "$HOME/.local/share/rea" tar -xzf rea_1.4.2_linux_amd64.tar.gz -C "$HOME/.local/share/rea" --strip-components=1 # 验证可执行 "$HOME/.local/share/rea/bin/rea" --version # 加入 PATH echo 'export PATH="$HOME/.local/share/rea/bin:$PATH"' >> ~/.bashrc source ~/.bashrc这套流程我在几台隔离环境里都用过,唯一需要注意的是--strip-components=1这个参数,取决于压缩包内部是不是带了一层顶层目录,解错了会得到一堆散落的文件。先tar -tzf看一眼结构再解,能省掉一次返工。
3. npm 全局安装:包管理器替你做的事和没做的事
3.1 npm i -g 在磁盘上到底发生了什么
一条npm i -g rea执行下去,实际发生的事情比大多数人以为的复杂,大致是这个顺序:
第一,npm 解析包名和版本范围,向配置的 registry 请求元数据,确定要装哪个具体版本,然后把 tarball 下载到本地缓存目录。
第二,把 tarball 解压到全局 prefix 下的lib/node_modules/rea目录里,同时按package.json把依赖递归装好。所以你在磁盘上看到的是一个完整的包目录,不是一个单文件。
第三,如果包的package.json里声明了bin字段,npm 会在全局 prefix 下的bin目录里创建一个指向真实入口的软链(Windows 上是一个.cmd垫片加一个.ps1垫片)。这一步才是“命令能用”的关键。
第四,执行postinstall脚本。这是最容易出问题的一环:很多 CLI 工具的 npm 包本身不含平台二进制,postinstall会根据当前平台去另外下载对应的二进制文件,放到包目录里的某个位置。这一步不走 npm 的 registry,走的是另一个下载源,因此失败原因和普通依赖安装失败完全不一样。
理解这个链条的意义在于,出问题时你能精确定位。报EACCES是第二步的权限问题;报404或ETIMEDOUT是第一步的 registry 问题;提示安装成功但命令不存在是第三步的 bin 软链没建或者 bin 目录不在 PATH 里;命令存在但一跑就报“找不到二进制”则是第四步的 postinstall 下载失败了。
3.2 标准操作序列
# 先确认 Node 与 npm 版本满足要求 node -v npm -v # 查看可安装版本,确认要装哪个 npm view rea versions --json | tail -n 20 # 装指定版本(推荐锁版本,理由见下) npm i -g rea@1.4.2 # 验证 type -a rea rea --version # 查看全局安装清单,确认版本号 npm ls -g --depth=0关于版本锁定,这里展开一句。npm i -g rea不带版本号时,npm 会按 registry 里的latest标签装最新版。对命令行工具来说,最新版意味着不受控的行为变化——输出格式变了、参数改了、默认配置变了,都可能让你前一天还好好的脚本第二天跑挂。除非你在主动追新,否则养成带版本号的习惯,升级当成一次有意识的动作来做。
npm ls -g --depth=0这个命令值得常备。它列的是全局顶层包,输出干净,一眼能看出机器上装了哪些全局命令以及各自版本。--depth=0的意思是只看顶层,不加这个参数会连依赖树一起刷屏。
3.3 权限问题的三种解法与取舍
EACCES: permission denied是 npm 全局安装最常见的报错之一,原因是全局 prefix 指向了需要 root 权限的目录,比如某些系统上默认就是/usr/local/lib/node_modules。
三种解法,我按推荐顺序排:
第一种,改全局 prefix 到用户目录。这是我最推荐的做法,一次配置长期受益,从此所有全局包都不需要 sudo。
# 建目录 mkdir -p "$HOME/.npm-global" # 设置全局 prefix npm config set prefix "$HOME/.npm-global" # 把 bin 目录加进 PATH,写进 shell 配置 echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc source ~/.bashrc # 验证生效 npm config get prefix第二种,用 Node 版本管理器(如 nvm、fnm、volta 这类工具)。它们本身就工作在用户目录下,全局包会装进当前 Node 版本对应的目录里,天然不需要提权。而且切 Node 版本时全局命令也跟着切,做多版本测试很方便。代价是多了一层环境复杂度,新机器上要先把版本管理器装好。
第三种,sudo npm i -g。能用,但我基本不用。它会把全局包目录的属主改成 root,导致之后不加 sudo 装包就报权限错误,形成“以后每一步都要 sudo”的恶性循环。如果已经踩进去了,用sudo chown -R $(id -u):$(id -g) <prefix目录>把属主改回来。
3.4 postinstall 下载二进制失败怎么破
前面提到过,很多 CLI 的 npm 包是“壳”,真正的二进制在postinstall阶段另外下载。这一步失败的典型表现是:npm i -g显示成功,rea --version也能跑,但一执行实际功能就报“binary not found”或者直接段错误。
排查思路是这样:
# 找到包的安装位置 npm root -g # 进去看看有没有平台二进制目录 ls -la "$(npm root -g)/rea" # 手动触发一次 postinstall,看真实报错 cd "$(npm root -g)/rea" && node ./scripts/install.js如果确认是二进制下载失败,而该项目的 npm 包支持自定义下载源,可以设置对应的环境变量,把下载源指到内网可达的地址。变量名各项目不同,通常是REA_BINARY_HOST或者npm_config_rea_binary_host这类形式,具体要看官方文档或者package.json里scripts字段的实现。
实在搞不定的话,我的做法是:用 npm 装壳、用 curl 方式把二进制补进去,然后把 bin 软链指过去。听起来土,但在隔离环境里是有效的兜底方案。
3.5 缓存、重装与彻底清理
npm 的缓存机制有时候会让“重装”变成假重装——你以为重新下了一遍,其实拿的还是缓存里的旧 tarball。
# 校验并清理缓存 npm cache verify npm cache clean --force # 强制重装某个包 npm i -g rea@1.4.2 --force # 彻底移除 npm uninstall -g rea # 手动清掉残留的配置与缓存目录(这一步 npm 不管) rm -rf ~/.config/rea ~/.cache/rea最后那行rm -rf需要注意:目录名是否真的是这两个,得看工具自身的实现。比较稳妥的做法是先在~/.config、~/.cache、~/.local/share下面ls | grep rea看一眼,确认之后再删。我见过有人误删了同名前缀的目录,把自己别的工具的配置清掉了。
4. 两种方式硬碰硬对比
4.1 全维度对照表
| 维度 | curl 脚本 | npm 全局 | 我的评价 |
|---|---|---|---|
| 首次安装耗时 | 快,通常几十秒 | 慢,依赖多时要一两分钟 | 差距在 CI 里会被放大 |
| 磁盘占用 | 小,单个产物目录 | 大,含依赖树 | 容器镜像里影响明显 |
| 前置环境 | 只要有 curl/wget | 需要 Node.js | 干净机器上 curl 优势大 |
| 版本可控性 | 靠环境变量,看脚本实现 | 原生支持精确版本 | npm 更规范 |
| 升级操作 | 重跑安装脚本 | 一条命令 | 都很简单,但 npm 更可预期 |
| 卸载彻底性 | 看脚本是否提供卸载 | 标准命令,需手清缓存 | npm 略好 |
| 多版本共存 | 改目录即可,天然支持 | 要切 prefix,麻烦 | curl 明显占优 |
| 离线部署 | 拷产物即可 | 需离线包或私有源 | curl 明显占优 |
| 可审计性 | 需要人工审阅脚本 | 有 registry 元数据和完整性校验 | npm 更让人放心 |
| 出错信息质量 | 参差,有时只报“失败” | 结构化,有错误码 | npm 更好排查 |
| 对系统的侵入 | 基本只加一个软链 | 引入全局包目录与缓存 | curl 更干净 |
4.2 三个最容易被忽略的差异
第一个是 PATH 的归属。curl 脚本装完之后,PATH 里的入口可能是脚本自己建的一个软链;npm 装完之后,PATH 里的入口是 npm 的全局 bin 目录里的软链。这两个软链指向的真实文件可能在不同位置,一旦你换了安装方式,旧软链不会自动消失,于是就出现了两份命令打架的情况。这就是我在开头说的那次“版本对不上”的根源。
第二个是卸载后的残留。npm 卸载只会删包目录和 bin 软链,运行时生成的配置目录、缓存目录、日志目录一概不动。curl 脚本一般也不提供卸载入口,删起来更没谱。所以不管用哪种方式,卸载时都要额外做一次人工清查:
# 卸载后确认有没有残留 ls -la ~/.config | grep -i rea ls -la ~/.cache | grep -i rea ls -la ~/.local/share | grep -i rea ls -l /usr/local/bin | grep -i rea ls -l ~/.npm-global/bin | grep -i rea第三个是多版本共存。这件事上 curl 方式有天然优势:装到两个不同目录,用软链或者alias切换就行。
# 准备两个版本目录 ls -d ~/.local/share/rea-* # 用 alias 临时切换(仅当前 shell 有效) alias rea14="$HOME/.local/share/rea-1.4.2/bin/rea" alias rea15="$HOME/.local/share/rea-1.5.0/bin/rea" # 或者用软链切换默认版本 ln -sfn "$HOME/.local/share/rea-1.5.0" "$HOME/.local/share/rea-current"npm 方式要做到同样的事,得准备两套 prefix,每次切换要改npm config set prefix,还会影响该 prefix 下的所有全局包,颗粒度太粗。所以如果你需要频繁在多个版本之间横跳做兼容性验证,我的建议是主版本用 npm 装,验证用的旧版本走 curl 方式装到独立目录,用alias调。两者互不干扰。
4.3 场景化选择建议
个人开发机,本身就在写 Node 项目:走 npm。环境已经具备,全局安装顺手,版本管理规范。
干净的 Linux 服务器,没有也不打算装 Node:走 curl。为了一个命令行工具装一整套 Node 运行时,不划算,还多了一堆需要持续打补丁的组件。
容器基础镜像:优先 curl 方式,并且务必锁死版本 + 校验哈希。npm 方式会往镜像里拉 Node 和依赖树,镜像体积能差出几十上百 MB,而且postinstall阶段需要额外网络访问,构建时容易失败。
CI 流水线:看情况。如果镜像里本来就有 Node,用 npm 加精确版本号最省事,npm ci那一套心智模型可以直接复用;如果没有,用 curl 下载固定版本的产物并校验哈希,比在流水线里现装 Node 快得多。
需要同时维护多个版本做兼容测试:curl 方式装多份到不同目录,用 alias 或软链切换。
5. 装不上、装上了跑不起来:排查实录
5.1 command not found 的排查链路
这个报错能覆盖安装问题的六成以上,按下面的顺序逐层排查,基本不会漏。
第一步,确认文件到底存不存在。
# 全局搜索一下可执行文件到底在哪 ls -l /usr/local/bin/rea ls -l ~/.local/bin/rea ls -l ~/.npm-global/bin/rea第二步,确认它在不在 PATH 里。
echo "$PATH" | tr ':' '\n'把输出和上一步找到的目录对一下。如果目录不在 PATH 里,那就是配置没生效,回到第 2.6 小节处理。
第三步,确认软链指向是否有效。软链指向的文件被删掉或者挪走,会出现“文件存在但不可执行”的状态,ls -l会显示一个红色的悬空链接。
readlink -f /usr/local/bin/rea ls -l "$(readlink -f /usr/local/bin/rea)"第四步,确认 shell 缓存。hash -r之后再试。
第五步,确认执行权限。chmod +x处理一下,尤其是从压缩包手动解压出来的产物,解压工具可能没有保留可执行位。
5.2 常见问题速查表
| 现象 | 最可能的原因 | 处理方式 |
|---|---|---|
command not found | 目录不在 PATH / 软链悬空 / shell 缓存 | 按 5.1 逐层查,hash -r |
Permission denied | 文件无执行位,或属主是 root | chmod +x;查属主,必要时chown |
EACCES安装报错 | npm 全局 prefix 需提权 | 改 prefix 到用户目录 |
exec format error | 架构不匹配 | 确认uname -m,换对应架构产物 |
GLIBC_2.xx not found | 系统运行时库版本过低 | 用静态编译产物或换基础镜像 |
| 安装成功但功能报错 | postinstall二进制未下载 | 手动触发,查下载源可达性 |
| 版本号与预期不符 | 机器上有多份,先命中了旧的 | type -a rea查全部,清旧版 |
| 下载卡住或超时 | registry 或产物源不可达 | 检查网络、换源、离线包 |
| 重装后行为没变 | 配置目录残留 / npm 缓存未清 | 清缓存,删配置目录 |
5.3 版本打架的定位手法
type -a rea会按 PATH 顺序列出所有同名命令,这个命令我强烈建议每个装完的人都跑一次。输出两行以上,就说明机器上有多个来源。
type -a rea # 输出示例: # rea is /home/user/.npm-global/bin/rea # rea is /usr/local/bin/rea排序在前面的那个会被优先执行。如果你想让某个版本优先,要么调 PATH 顺序,要么把不要的那个删掉。别放任两份共存,早晚会坑到你自己——尤其是当两份版本号不一样、行为有差异的时候,报错信息看起来会完全莫名其妙。
5.4 网络受限环境的处理思路
超时和下载失败在受限环境里很常见,处理思路分三层。
第一层是延长超时和增加重试次数,对付偶发波动:
npm config set fetch-timeout 120000 npm config set fetch-retries 3第二层是换包源地址,指向内网可达的私有源。这里不展开具体配置,各团队的基础设施不一样,思路是把registry指向一个内网能访问的地址。
第三层是离线方案。npm 有离线包的做法,可以把包和依赖打包成 tarball 带到目标机器上装;curl 方式更直接,把产物和校验文件一起拷过去就行。在严格隔离的环境里,我基本只用 curl 方式,因为它对网络的依赖只有一次下载,而且这次下载可以完全发生在另一台机器上。
6. 卸载、升级与长期维护习惯
6.1 干净的卸载流程
curl 方式的卸载,取决于安装脚本有没有提供卸载入口。有的话优先用,没有就手动来:
# 断掉软链 sudo rm -f /usr/local/bin/rea # 删掉产物目录 rm -rf "$HOME/.local/share/rea" # 清理 shell 配置里加的那行 PATH(手工编辑更安全) # 编辑 ~/.bashrc 或 ~/.zshrc,删掉 export PATH 那行npm 方式的卸载:
npm uninstall -g rea npm cache verify # 再手工清理配置与缓存目录两件事一定要做:一是删软链,二是清配置目录。前者决定命令还在不在,后者决定重装之后会不会继承旧状态。我遇到过重装后配置还是旧的,就是因为~/.config/rea没清。
6.2 升级策略:锁版本还是追最新
我的做法分机器:开发机可以适度追新,装个最新版试功能;CI 和内网服务器一律锁死版本,升级走一次显式的变更流程,改版本号、跑一遍冒烟测试、提交。
锁版本的具体做法:npm 方式写rea@1.4.2,或者维护一份安装清单;curl 方式把版本号写进安装命令,同时把校验哈希也写进去,这样即便上游产物被替换,安装也会失败而不是悄悄装上另一个东西。
# curl 方式锁版本的示例写法 REA_VERSION=1.4.2 bash rea-install.sh sha256sum -c rea_1.4.2_checksums.txt6.3 我自己的落地习惯
最后分享几条我踩过坑之后固化下来的习惯,都是些小动作,但省下的时间远超过做它们的成本。
第一,装之前先type -a rea,确认现状。这一条能避免八九成的版本混乱。
第二,装完立刻跑三件事:type -a rea、rea --version、rea <某个无害的子命令>。只看版本号不够,有些情况版本号能打出来但实际功能跑不了,因为二进制没下全。
第三,安装命令一定带版本号,不进 shell 历史里留一条不带版本的裸命令,防止哪天顺手按上箭头重跑,稀里糊涂升了级。
第四,涉及提权的安装,先把脚本下载下来看一眼再执行,尤其是带curl | bash的写法。审阅脚本花三分钟,比事后排查半天划算。
第五,在一台机器上只用一种安装方式,不要两种混装。真想共存,就装到不同目录并用 alias 区分,让它们从名字上就分得开。
第六,卸载时手工清一遍配置和缓存目录。这一步没有任何工具会帮你做,但它是“重装之后行为异常”的头号原因。
这套习惯跑下来,最近一年多我在各种环境里装 rea 没再翻过车。如果你的场景比较特殊,比如完全隔离的内网、只读文件系统、或者需要在一台机器上并行跑多个版本,优先按前面几节的思路拆解,大部分问题都能归到“产物架构不对”、“PATH 没生效”、“二进制没下全”、“旧版本没清干净”这四类里,按类去查,比漫无目的地试要快得多。