为什么有 Seashell 2 和 Bashert
关联
- https://github.com/chongwish/seashell
- https://github.com/chongwish/seashell2
- https://github.com/chongwish/bashert
缘起
早在 13 左右的时候,我就特别依赖于在容器运行 GUI 应用,从配置麻烦的 Lxc 到占用资源的 Docker,最终到 Lxd 和 Systemd-nspawn,其间需要写大量的 ShellScript 来使容器里的 GUI 能够正常在主机里的运行,如我会为 Firefox 浏览器和 Steam 游戏平台各写一个脚本,里面有相当一部分重复内容:
- 容器维护(容器运行和初始化)
- 发行版相关维护(包安装以及系统配置)
- Device(如 GPU 等的)
- Xorg(Socket 和 Xauth)
- Audio
- 环境变量
- ……
虽然,ShellScript 本身可以 source
,但是是非常难以项目化,这对于一个开发多年的人来说也是非常难以接受的,所以便有了我的第一次尝试:Seashell。
Seashell 并没有太多“对于一个 ShellScript 库该如何写“去做深入思考,而是为了应用层面的实现去临时拼凑出的一盘杂碎,像对于导入其他脚本,临时有像 C/C++ 那样 include
的 idea,又冒出像 Java 那样 import
的 idea,加了太多草率实现的杂音,其中一部分还跟自己初衷有点违背,而且想兼容 zsh 和 bash,其实又大部分没法做到。
总之,对于没有深思过的 Seashell,我一直都想抛弃掉,奈何没时间和应用层面脚本一直都可以用,就一直搁置着。
重来
在没上班的日子里,玩也玩得够久了,于是久违的”项目化 ShellScript”就被提上日程,心想就折腾个 Seashell 2 吧。
重新实现的 Seashell 2,并不是跟之前一样,以应用来驱动库开发的,而是自己脑补库所需:
- 核心库与应用脚本分开,于是单独有了 Bashert 这个应用脚本项目
- 更加清晰的模块化和命名空间,语义更加一致
- 尽量的无入侵性,对于无项目化的脚本基本没有迁移成本
- 能标记最终脚本的样子,方便调试
- 核心库提供更好的 Hooks,能以后更好拓展功能
- 核心库提供生成应用脚本项目的脚手架
- 核心库能在 zsh 和 bash 下工作,但是应用脚本的兼容交给脚本人
- 提供返回值,而非 Shell 子能返回状态值
- 能够将模块化的脚本打包成一个单一脚本,方便部署
- 提供交互模式,输出模式和运行模式
- ……
然后一步一步去落实这些规划的功能。确实在有规划之后,实现功能比当初那种一头扎进泥泞去四处打补丁要简单且科学得多。
应用
Seashell 2 作为一个可以项目化 ShellScript 的库,它应该是稳定的且独立于应用脚本项目。那么我们需要思考一个 ShellScript 项目化后,它的目录结构应该是怎么样的。理想情况下,我觉得核心库和应用库得有一致的结构,才能减轻心智负担,最简单的结构可能是:
. # 库的当前目录
├── bin/ # 应用脚本入口
├── mod # 库的定义
├── src/ # 模块代码实现
└── vendor/ # 第三方库
一致的结构,可以方便由 Seashell 2 去提供一个脚手架帮助创建生成,Bashert 项目就是在 Seashell 2 提供的 seashellist
脚手架工具去生成的。Bashert 是一个应用层面的库,正如其名字,里面写的都是 BashScript,而非通用的 ShellScript,日常生活和办公,都有太多重复性且可以划分所属的功能,是很适合项目化组织的,如:
- 命令行解析
- 容器管理
- 虚拟机管理
- 音频转换
- 视频转换
- 爬虫
- 系统管理
- ……
作为独立应用的 Bashert,除了功能实现和功能复用及功能使用,还能作为第三方的库被引用,最大化重复利用脚本。