Ubuntu 26.10「Stonking Stingray」将成为第一个把 GNU coreutils 全面替换为 Rust 实现的 Ubuntu 版本。ls、cat、chmod、du 等每天都会调用的基础命令,底层实现将由 uutils 提供。
这不是给系统额外安装一套 Rust 工具,而是把发行版最底层、最常被依赖的一组用户态工具换成内存安全实现。对普通用户来说,命令行接口大体不变;对发行版维护者和开发者来说,变化则涉及兼容性、性能、调试方式以及供应链管理。
从单个工具试点到整套 coreutils
Canonical 从 2025 年开始推进 Ubuntu 的“锈化”路线,Ubuntu 25.10 是这一计划较早的落地版本。随着迁移范围扩大,Ubuntu 26.10 将最后一组 GNU 核心工具也切换到 uutils。
uutils 是一套使用 Rust 编写、兼容 Unix 命令行为的工具集合。它的目标不是创造一套全新的命令行语法,而是在保留常见命令接口的同时,利用 Rust 的类型系统和所有权模型减少一类典型的内存安全问题,例如越界访问、释放后使用和部分数据竞争风险。
这里的“内存安全”并不等于“命令永远安全”。rm 仍然可能删除错误的文件,chmod 仍然可能配置出过宽的权限,shell 脚本也仍然可能存在注入漏洞。Rust 主要改善的是工具自身实现层面的缺陷,不能替代权限设计、输入校验和运维审查。
对日常命令意味着什么
对于简单用法,迁移通常应该是透明的。例如下面这些命令的使用方式不会因为实现语言变化而改变:
ls -lah /var/log
cat /etc/os-release
du -sh /var/cache
chmod 640 ./secrets.env
真正需要关注的是边界行为。长期运行的脚本可能依赖以下细节:
- 特定的错误码和失败条件;
--help或--version输出格式;- 特殊文件名、非 UTF-8 文件名和换行符的处理;
- 排序规则、时间格式和 locale 行为;
- GNU 扩展参数是否完整保留;
- 大文件、符号链接、管道和权限异常时的行为。
因此,“命令名相同”不代表“每个字节都兼容”。尤其是构建系统、发行版打包脚本和 CI 流程,往往比交互式命令更容易暴露差异。
在升级前做一轮兼容性检查
如果你维护的是服务器镜像或生产脚本,可以先把常用命令集中跑一遍,记录退出码和关键输出。下面的示例不依赖特定 Ubuntu 版本,适合在测试环境中改造使用:
#!/usr/bin/env bash
set -u
workdir="$(mktemp -d)"
trap 'rm -rf "$workdir"' EXIT
printf 'beta\nalpha\n' > "$workdir/names.txt"
printf 'sample data\n' > "$workdir/data.txt"
ln -s "$workdir/data.txt" "$workdir/data.link"
run_check() {
local name="$1"
shift
printf '\n--- %s ---\n' "$name"
"$@"
printf 'exit_code=%s\n' "$?"
}
run_check 'ls' ls -la -- "$workdir"
run_check 'cat' cat -- "$workdir/names.txt"
run_check 'du' du -sh -- "$workdir"
run_check 'stat' stat -- "$workdir/data.link"
run_check 'sort' sort -- "$workdir/names.txt"
printf '\nVersions:\n'
command -v ls cat du stat sort
ls --version 2>/dev/null | head -n 1 || true
运行前把脚本放在测试机或容器中执行,不要直接在生产目录创建临时文件。对关键脚本,还可以分别在旧环境和目标 Ubuntu 版本中保存输出,再用 diff -u 比较:
./check-coreutils.sh > old-output.txt 2>&1
# 在目标系统中再次运行
./check-coreutils.sh > new-output.txt 2>&1
diff -u old-output.txt new-output.txt || true
这类检查不能证明完全兼容,但能快速发现版本信息、排序结果、符号链接处理和错误码方面的变化。若脚本只需要机器可读结果,优先使用稳定的格式选项,并避免解析面向人的默认输出。
Rust 化带来的收益与代价
最大的收益是基础工具实现使用了内存安全语言。coreutils 位于大量脚本和服务的调用链上,哪怕单个工具本身很小,覆盖面也非常广。降低底层实现出现内存错误的概率,有助于减少一类难以定位、影响范围可能很大的安全问题。
同时,迁移也会带来现实成本:
- 兼容性验证需要持续进行。 GNU coreutils 的行为经过多年积累,项目既要兼容常见用法,也要处理大量边界条件。
- 性能不能只看语言。 Rust 可以生成高效的本地代码,但最终表现还取决于算法、系统调用、启动开销和编译选项,应使用真实工作负载测试。
- 调试知识需要更新。 维护者可能需要同时理解 shell 行为、uutils 实现和 Rust 依赖链,而不是只查看 GNU 工具的历史实现。
- 内存安全不是完整安全模型。 权限错误、路径穿越、竞态条件和命令注入仍然需要在上层解决。
给团队的落地建议
如果你的系统会从 Ubuntu 25.10 或更早版本升级到 Ubuntu 26.10,可以按下面的顺序降低风险:
- 为核心脚本建立测试样例,覆盖空输入、特殊文件名、符号链接、大文件和权限异常;
- 在 CI 中固定 locale、时区和环境变量,避免把显示格式变化误判为业务结果;
- 不要依赖未文档化的错误输出文本,用退出码和明确的机器可读选项判断结果;
- 为基础镜像设置可回滚版本,并在升级前验证构建工具、安装脚本和启动脚本;
- 对文件操作使用绝对路径、明确的
--分隔符和最小权限,别把安全责任交给底层命令实现。
Ubuntu 26.10 的 coreutils 全面 Rust 化,重要的不只是“把 C 换成 Rust”,而是发行版开始重新审视最基础软件的安全边界。对使用者而言,最稳妥的策略不是假设一切都不会变,也不是因为实现语言变化就停止升级,而是在测试环境中验证真正依赖的命令行为,再有计划地推进迁移。