# 46-实例共享工具(jq / ripgrep / ffmpeg)(2026-09-11 落地) ## 背景与动机 档案 38a 曾回答「Playwright 等包是否每个用户都要装一份」,结论是**宿主装一次全员共享** (`/usr` 已 ro-bind = 零改造通道);当时把 `rg` / `jq` / `ffmpeg` 列为待补的**环境基线**,但**一直未执行**。 用户本次追问「还有一些待处理的任务没确认和执行吧,比如 ffmpeg」→ 本条即补齐。 ## 结论:不需要每个用户单独安装 | 依据 | 说明 | |---|---| | 实例内 `/usr` 是 **ro-bind**,且 `/usr/local/bin` 在实例 PATH **首位** | **宿主装一次 → 全部实例(含新用户)立即可见**,零代码、**无需重启实例** | | 用户侧本来就装不上 | `/usr` 只读 + 无 sudo(实测 `touch /usr/local/lib/x` = Read-only) | | 每人一份的代价 | 重复占磁盘(宿主 **无磁盘配额**)、版本不一致、还会落进工作区被 `#/files` 展示 | ## 实现 新增 **`scripts/install-shared-tools.sh`**(幂等 / 固定版本 / **官方 sha256 校验** / 可离线 / 可 `--force`): | 工具 | 版本 | 来源与校验 | |---|---|---| | `jq` | **1.8.2** | 官方静态单文件 + `sha256sum.txt` | | `rg`(ripgrep) | **15.2.0** | `x86_64-unknown-linux-musl`(静态,无 glibc 依赖)+ 官方 `.sha256` | | `ffmpeg` / `ffprobe` | master(N-126492) | **BtbN FFmpeg-Builds 静态构建**(单二进制、自带全部编解码库)+ `checksums.sha256` | - 安装位:`/usr/local/dsh-runtime/bin/`,并在 `/usr/local/bin/` 建软链(**已在实例 PATH 首位**)。 - 生成清单 `/usr/local/dsh-runtime/SHARED-TOOLS.md`(版本 + 时间),供迁移与审计。 - **迁移打包单元 = `/usr/local/dsh-runtime/` 一个目录**(与档案 42 的 Python 同目录): `tar czf dsh-runtime.tar.gz -C /usr/local dsh-runtime` → 目标机解压回原位 + 重跑两个安装脚本。 **为什么选静态构建**:`ffmpeg` 走 `dnf` 需要 RPM Fusion、且依赖散落在 `/usr/lib64`,迁移不平滑; 静态单文件自包含、**一个目录即迁移单元**,与用户的「方便迁移整体打包」要求一致。 ## 验证记录(沙箱内 uid 100002 实测) | 检查 | 结果 | |---|---| | 可见性 | `jq` / `rg` / `ffmpeg` / `ffprobe` 全部 `/usr/local/bin/*` | | 版本 | `jq-1.8.2`;`ripgrep 15.2.0 (rev e89fff89ac)`;`ffmpeg version N-126492-…` | | `jq` 真跑 | `echo '{"a":{"b":[1,2,3]}}' \| jq -c '.a.b\|length'` → **3** | | `rg` 真跑 | `rg -i world /tmp/t.txt` → **WORLD** | | `ffmpeg` 真跑 | 生成 440Hz 正弦并编码 mp3 → **产物 8585 字节** ✅ | | `ffprobe` 真跑 | 读出该文件编码 = **mp3** | | 校验 | 三个包的 sha256 均与官方发布文件一致 | ## 顺带 `scripts/runtime-baseline.cjs` 的基线纳入 `rg` / `jq` / `ffmpeg`(版本漂移会告警)。 ⚠️ ffmpeg 的版本号形如 `N-126492-gefb0a7e5e7`(**不含 `x.y` 形式**), 故其提取用 `ffmpeg version (\S+)` 而非通用的 `\d+\.\d+` 规则。 ## 注意 / 后续 - **新增共享工具的正确做法**:优先找**静态单文件**发行版 → 放 `/usr/local/dsh-runtime/bin` + 软链到 `/usr/local/bin` → 更新 `SHARED-TOOLS.md` → 跑 `runtime-baseline.cjs --accept` 刷新基线。 - **Playwright(仍未做)**:它**不是**单文件,除浏览器二进制外还缺 **11 个系统 `.so`** (`libnss3`/`libgbm`/`libatk`/`libcups`/`libdrm`/`libxkbcommon` …)。系统库只能 `dnf install` (宿主装一次同样全员可见 ✅),浏览器二进制建议放共享位并用 `PLAYWRIGHT_BROWSERS_PATH` 指定 —— 但**注入该 env 属于 R5「给实例注入新 env」= 扩大**,需先出「权限影响评估」并取得确认,故**未做**。