GitHub 项目 amatsuda/rubish 做了一件很绕、也很有意思的事:用纯 Ruby 写一个 Unix shell。
它不是把 Ruby 当脚本语言塞进 shell,而是把 shell 语法解析、编译成 Ruby 代码,再交给 Ruby VM 执行。项目采用 MIT 许可证。README 里写得很满:目标是 Fully Bash-compatible,现有 Bash 脚本无需修改即可运行;不兼容会被视为 bug。
这句话要拆开看。
“兼容 Bash”目前是项目方目标和维护态度,不是第三方已经验证过的成熟结论。Rubish 的价值也不在“又来了一个 shell”。真正值得看的,是它试图把 Bash 兼容层、Ruby 语法和 Ruby 程序内嵌 API 放进同一个执行环境。
Rubish 不是换壳,变化在执行路径
Rubish 可以作为交互 shell 使用,也支持 rubish -c 执行单条命令、运行脚本,甚至作为 login shell。它还提供 Ruby 程序内嵌 API,比如创建 Rubish::REPL,调用 tokenize、parse、completion、prompt segments 等接口。
这意味着它面向的不只是终端用户。终端模拟器、IDE 插件、GUI 前端也可以在 Ruby 进程里驱动一段 shell 会话。
核心差异可以压成一张表:
| 对比项 | Bash / Zsh 常规路线 | Rubish 路线 | 现实判断 |
|---|---|---|---|
| 执行机制 | shell 自身解释执行 | shell 语法编译成 Ruby 代码,由 Ruby VM 执行 | Ruby 集成更顺,但兼容压力更大 |
| 脚本目标 | Bash/POSIX 生态 | 项目方声称 Bash 全特性兼容 | 只能先按项目声明理解,不能当成生产验证 |
| 扩展方式 | shell 函数、插件、补全脚本 | Ruby 条件、块、lambda、内联 Ruby、方法链 | Ruby 用户更自然,普通 shell 用户要重新适应 |
| 嵌入能力 | 多靠进程、文本协议、外部调用 | Ruby 进程内 API | 更适合工具作者做实验 |
所以,Rubish 的主线不是“我要打败 Bash”。
更准确的说法是:它想在 Ruby 运行时里做一个 Bash 兼容执行层。这个定位窄一些,但也更有辨识度。
对 Ruby 开发者来说,这会减少一类切换成本。日常在 Rails、Bundler、rbenv、Ruby 脚本和 shell one-liner 之间来回跳的人,最容易理解它的吸引力。
对团队来说,动作应该相反:不要急着迁移默认 shell。可以拿个人脚本、项目内工具、非关键 CI 辅助脚本试一圈,但别把它直接放到生产发布链路里承担 Bash 替代职责。
它比 Bash 多出的,是 Ruby 用户熟悉的写法
Rubish 最强的标签是深度 Ruby 集成。
它允许在 if、while、until 中用 { } 包裹 Ruby 表达式当条件。命令可以写成 ls('-la') 这种方法调用。管道可以写成 ls().sort.uniq。命令输出也能接 .each、.map、.select 这类 Ruby 迭代块,按行处理。
它还支持内联 Ruby、Ruby 数组和正则字面量、-> { } lambda、Ruby 风格 def...end 函数定义,以及用 Ruby 函数生成 prompt。
这些能力不是为了让 shell 语法更花。它解决的是一个老问题:很多命令行任务本来就夹在 shell、awk、sed、Ruby one-liner 之间。Rubish 试图把这些工作收进一个语法空间里。
举个判断层面的差别:
| 使用者 | 现在更适合怎么做 | 不建议怎么做 |
|---|---|---|
| Ruby 开发者 | 作为交互 shell、个人脚本执行器、项目本地 .rubishrc 试用 | 直接替换团队默认 shell |
| 终端 / IDE 工具作者 | 研究它的解析、补全、prompt、REPL API | 只把它当另一个命令解释器看 |
| 普通 Bash 用户 | 观望兼容性测试和边界案例 | 为了新语法立刻迁移 |
还有一个很现实的功能是 lazy_load。它可以把 rbenv、nvm、pyenv 这类较慢初始化放到后台线程处理,并在下一次 prompt 前应用结果。
这点不玄。很多开发者的 shell 启动慢,并不是 shell 本身多慢,而是版本管理器、补全脚本、环境初始化一层层叠上去。Rubish 至少把这个痛点摆到了台面上。
真正的门槛是兼容性和安全边界
Ruby 集成提高表达力,也会扩大风险面。
如果一个脚本里可以混入内联 Ruby、lambda、块和 Ruby 条件,它就不再只是传统 shell 脚本。执行不可信脚本时,风险模型也变了。
Rubish 提供 rubish -r restricted mode,用来关闭 Ruby 集成功能,只允许标准 shell 语法。被关闭的能力包括内联 Ruby、lambda、块、Ruby 条件和数组字面量。
这个设计很关键。它说明作者知道问题在哪里:强表达能力不能默认带进所有脚本场景。
但 restricted mode 也需要单独验证。它是否足够隔离 Ruby 能力?边界案例怎么处理?复杂 Bash 行为、子进程控制、信号、补全、长时间交互和性能表现能不能稳定?这些目前都不能靠 README 一句话解决。
接下来最该看的不是 star 数,也不是示例语法多漂亮,而是三件事:
- Bash 兼容测试覆盖到什么程度,尤其是复杂脚本和历史边角行为。
rubish -r是否能清楚隔离 Ruby 集成功能,适合执行不可信脚本。- 交互使用时,子进程、信号、补全、prompt、启动速度和长时间运行是否可靠。
Shell 是低层日用品。它可以不性感,但不能经常出错。一次脚本行为不一致,就足够让人退回老工具。
Rubish 现在最合适的位置,是给 Ruby 开发者和工具作者一个可试验的新执行环境。它如果真能站住,靠的也不会是“语法好看”,而是 Bash 兼容、Ruby 集成和安全模式三件事能同时过关。
这很难。
也正因为难,它才比普通的“新 shell 项目”更值得看一眼。
