https://github.com/adoyle-h/lobash
看名字你或许猜到了,这是一个受到 JS 的 Lodash 启发的,专用于 Bash 编程的类库。
Bash 脚本的坑很多,我期望能写一个类库,把复杂的东西封装到简单的函数(模块)里,一个函数只做一件事情。以此来增强开发体验。
我已经写了 90 个模块,近 500 个单测,大致 API 和开发模式已经稳定。
我曾尝试想将 Lobash 支持 Zsh 的,搭完测试框架和环境,跑了一下测试发现,Zsh 和 Bash 还有很多不一样的地方。所以决定放弃支持 Zsh,可能哪天我会再写个 Lozsh 库。
我在自己的 Dotfiles 里试吃了自己的狗粮,没有遇到什么问题。所以来试用一下吧,有什么感想提 Issue 或在这个帖子里留言即可。提 Issue 请尽量用英文,用中文也可以。
如果觉得有意思,欢迎与我一起共建。
如果觉得不错,请点一下 Star,让我有动力继续开发,谢谢。
发布了 v0.3.0 版本,主要改动是条件判断都支持了 return 0/1 的方式。但有不兼容之前版本的修改。
为了保持可读性,考虑到项目初期用的人不多,于是产生了不兼容的修改,各位见谅。以后应该不会有这种不兼容修改了。
具体见 changelog
这个帖子里提到的问题应该都修改好了。后续有问题请到 issue 里提问。
最后一条 APPEND 发布了 0.4.0 版本,主要做了以下改动
其他具体见 changelog。
最后,欢迎大家提意见,或者把这个库分享给其他人。
1
dandycheung 2019-07-02 09:51:55 +08:00 via iPhone
手动点赞,挺好。
|
2
Meltdown 2019-07-02 09:58:21 +08:00 via Android
不错,收藏
|
3
wutiantong 2019-07-02 10:00:43 +08:00
看起来不错
|
4
pony279 2019-07-02 10:08:49 +08:00 10
无意冒犯,还是忍不住泼点凉水,bash 虽然可以当编成语言用,但这怕不是 shell 脚本的初衷
100 行内还搞不定的事情,还坚持用 bash 就是糟糕的选择 写 bash 的人就应该熟悉语法,就是追求极简,用 l.is_file() { [[ -f ${1:-} ]] && echo true || echo false } if [ $(l.is_file $filename) == "true" ] ; ... fi 这样罗嗦的方式来替代 if [ -f "$filename" ] ; then ... fi 是不明智的选择 如果有用各种基础库的需求,还不如重新设计一个语言,bash 干这个真的特别别扭 |
5
adoyle OP @pony279
> 100 行内还搞不定的事情,还坚持用 bash 就是糟糕的选择 坚持还是不坚持,是用户的理想判断和选择自由,Lobash 只是为选择 Bash 提供一些帮助而已。100 行内搞不定的事情,确实可以考虑其他语言。但为什么要选择 bash 呢?我觉得在于依赖,比如你用 nodejs 写,运行你程序的用户需要在运行平台装 node,依赖的版本管理升级怎么办,这会引入更多问题。bash 和 linux 命令行大多数是通用的,虽然我这个库需要用 bash 4.4,而现实上 linux 装的大多数是 bash 4.3,但是升级一下 bash 还是很简单的事。 > 写 bash 的人就应该熟悉语法,就是追求极简 这是对于熟练工而言的,当你只是想用 bash 用管道去写个小程序,当你去翻 bash 手册熟悉语法越陷越深,就我的经验而看 bash 有是很多坑的,学习的过程是比较痛苦的。 is_ 系列为什么要这么啰嗦的返回 true 或者 false ?请看这个链接 https://github.com/adoyle-h/lobash/blob/develop/doc/how-to-write-functions.md#how-to-return-a-boolean-value |
6
0x11901 2019-07-02 10:28:02 +08:00
没有 API 文档吗?不可能 90 个模块需要我自己看哪个能用上吧……
还有实名反对楼上的观点。 |
7
adoyle OP 刚刚打错字了,理想判断 => 理性判断
|
8
adoyle OP @0x11901 请仔细看 README,https://github.com/adoyle-h/lobash#module-usages
这里有用法,描述,例子,单测的链接,晚上有空我再加个跳到源代码的链接。 |
9
hgjian 2019-07-02 10:33:39 +08:00 via Android
没有中文文档,看不懂哦,我英语差。
|
10
adoyle OP @hgjian 不好意思,以后也不会加中文文档的,英语差可以翻字典一个个词来看,我也是从英语渣渐渐成长的,相信你也可以做到。
|
11
jorneyr 2019-07-02 10:38:04 +08:00
挺好的
|
12
YK46PTT 2019-07-02 10:40:01 +08:00
挺好的, 之前也想找这样的 repo
|
13
zhanglp888 2019-07-02 10:52:09 +08:00
赞,感动!
repo 现有的模块,已经能完成我基本所有的需求了 等我仔细看一下单测,再谈感想~ |
14
pony279 2019-07-02 10:54:31 +08:00 1
> 我觉得在于依赖,比如你用 nodejs 写,运行你程序的用户需要在运行平台装 node,依赖的版本管理升级怎么办,这会引入更多问题。bash 和 linux 命令行大多数是通用的,虽然我这个库需要用 bash 4.4,而现实上 linux 装的大多数是 bash 4.3,但是升级一下 bash 还是很简单的事。
1. 这取决于你的业务。如果本身没有什么依赖,能用 bash 写的,同样可以用兼容性好的 node 脚本完成。就是因为逻辑复杂了,才会不得不选择 node, java, go, python, php,才会有各种依赖和版本管理。 2. 升级 bash 4.4 就是修改你的系统工具了,至少需要 root 权限吧,有 root 权限安装个 node/php/python 也是一条命令的事情。 > is_ 系列为什么要这么啰嗦的返回 true 或者 false ?请看这个链接 > The way 2 cannot distinguish the false and the exception occurs in function (it will return other codes if your shell has set -o errexit and set -o pipefail). So the choice 1 is better. return 0/1 / echo true/false 确实有这样的优缺点 长期做开发的人确实有严谨的逻辑 但是,从我多年写过的 bash 脚本来看,我根本不需要这些啊,如果按照你的考虑,每条都严谨处理,你的 l.is_file 会变成这样: isFile=$(l.is_file $filename) # when exception with set -e, the script will abort immediately if [ "$isFile" == "true" ] then ... fi 为了极度的严谨罗嗦正这样,何必呢。有这样的需求,正统的编成语言才是最优解。 再退一步想想,is_file 这种底层只依赖简单系统调用的东西都能异常,怕是整个操作系统即将崩溃了,就好比天塌下来了,为啥要关心桌子上的水杯还在晃。 |
15
dandycheung 2019-07-02 11:02:50 +08:00 via iPhone
@pony279 总会有一些我们每个人都想象不到的场景的,作者的努力让人有了更多的选择,世界也没有因此而更糟。我为什么需要呢,因为我有一块用一块淘汰了的 1GB 或者 2GB 的 TF 卡做系统盘的 Pi 板子,装个 Python 就有点嫌大,bash 刚刚好,就这样。
|
16
Karpov 2019-07-02 11:04:28 +08:00 via iPhone
对于 bash 场景有了很好的选择,谢谢分享
|
17
pony279 2019-07-02 11:10:03 +08:00
@dandycheung 我并没有打算否定作者的努力,我只是从我个人经验和实用性的角度解释这类工具的必要性。作者有他坚持的理由,我有不需要的理由,就是这么简单啊
|
18
adoyle OP @pony279
> 2. 升级 bash 4.4 就是修改你的系统工具了,至少需要 root 权限吧,有 root 权限安装个 node/php/python 也是一条命令的事情。 全局安装了这些,多个不同的项目有相同依赖就会有版本冲突和不兼容的风险,所以我通常不推荐全局安装,用 nvm,rvm,gvm 来装各种语言环境。 在 Lobash 这个库我也考虑如果有多个类库来使用 Lobash,其他项目间接依赖多版本的 Lobash 怎么办。因此我使用 ./build + PREFIX + 时间戳 的方式来生成项目自己唯一的 lobash.bash。 用户选择什么方案,就要考虑这个方案的成本,具体细节具体分析吧。我只是为 Bash 增加使用的可能性,并不影响用户的判断,用户需要自己来判断自己需要什么。 > 为了极度的严谨罗嗦正这样,何必呢。有这样的需求,正统的编成语言才是最优解。 恩,你说的有道理。因为我急于开发出这套框架来应用,return 0 1 在我看来不理想,为了 API 格式统一我先选择了严谨的写法,严谨虽然麻烦但总不会出错。你的意见我需要一点时间再考虑,如果确实没问题,可以新增一批模块,提供更多方便的选择。 |
19
yidinghe 2019-07-02 11:14:30 +08:00
我是支持楼主的,我自己也写过简单的运维脚本 https://gitee.com/yidinghe/codes/394evuspjc1qfrwyzd2no37,只是用来启动和停止进程。另外我开启了 issue #2。
|
20
rrfeng 2019-07-02 11:23:22 +08:00 via Android
支持楼主的想法做法
但是实用性确实有限… |
22
hljjhb 2019-07-02 11:31:24 +08:00 via Android
bash 4.4+ 基本与服务器无缘了
|
23
iwtbauh 2019-07-02 11:35:36 +08:00 via Android 3
@pony279 #4
Linux 内核源码里面也有很多几百行的 shell 脚本。而且是 POSIX shell 脚本,连 bash 都不是。 如果你看一个发行版的源码树,你会发现很大的 shell 脚本多的是。 为什么他们要写这么长的 shell 脚本呢。原因在于需求决定了使用 shell 比其他语言更合适。源码树里还有大量的 perl 脚本和 c 代码,为什么这时候不用 shell,自然是因为解决相应的需求用另外的语言合适。而不是代码行数决定的。 “ 100 行以上不选 bash ”就像超过 100 米长的路不能骑单车一样可笑。 |
24
ps1aniuge 2019-07-02 11:45:11 +08:00 4
1 你用 bash 写 bash 库,我真的很佩服你。
2 我的观点:把 bash 扔到角落里,基本不用。99%用 powershell。 3 powershell win,linux 通用。 4 你的库对强类型支持如何?用你的库能实现布尔么? powershell 有强类型。比如布尔,py 也有。还有 fish。 py 的主要问题是没有命令行管道。fish 的主要问题是它没有强类型库做底层支撑。 5 依赖。 5.1 啥也不装就啥功能都有。---无法实现。 5.2go 次好。但是 go 并没有提供命令行框架。也没有提供命令行。 5.3powershell 提供一揽子框架。安装简单。依赖比 py 好。没有绝对路径。 5.4py 没提供命令行,管道。安装有时需要编译。 结论:powershell 是最好的。 6tab 补全。 bash 一手好牌打烂了,还坑了 go。 用 go 开发的命令行程序,依赖 bash,依赖 bash 补全,那就要写补全脚本, https://www.v2ex.com/t/563986#reply0 7 调试 shell 不行。 用 vscode+powershell,帮 shell 脚本实现单步,断点的例子 https://www.v2ex.com/t/575848#reply1 最终结论: 1bash 还有救么? 2 所有给 bash 续命的,都是幺蛾子,在 powershell 面前不值一提。命真续不了了。 3powershell 的主要优势 3.1win,linux 通用 3.2 后台硬(.net 库强) 3.3 常用库基本齐全。 3.4 有像 pypi 那样的官方,第三方存储库。一件安装任何扩展。有 n 大企业支持,给它发布模块。 3.5 有 命令行。 管道。 对象。管道前后传强类型对象。从 win 到 linux,用 ssh 远程传对象。 远程调试。 自动上传脚本到远程。 powershell 才是爱脚本人的未来,楼主既然这么强。何不编写 powershell 的脚本,放在 [powershell 画廊] 。帮助完善 powershell ? powershell [强] [简] 死你! |
25
adoyle OP @hljjhb 诶,我也很纠结。`inherit_errexit` 选项 bash 4.4 才有,`Nameref` 4.3 才有,这两个我很难割舍。
`inherit_errexit` 保证程序按我理想的来,如果没有这个保证,就会有各种坑,具体看[这个链接]( https://mywiki.wooledge.org/BashFAQ/105),这对 bash 脚本开发者是个负担。 `Nameref` 主要是传递数组很方便。 bash 4.4+ 是基本与服务器无缘了,最多只能在 docker 里跑,但都能跑 docker 了,环境依赖问题就没有了,想用什么语言都行何必用 bash。 |
26
ps1aniuge 2019-07-02 12:06:23 +08:00
一个老烂番茄,你去顶,将会顶出一头臭汁。你应该去踩 2 脚。
powershell 不是开源的? 不是免费的? 问:powershell 啥时候开源(+免费)的? 答: 2015 年小范围内部开源,2016 年开发者大会上,正式法律开源。 问:开源后的 powershell,属于谁的财产? 答: 在遵守其开源协议的前提下。powershell 开源后。属于 [社区财产] 或 [任何人财产] 。 问:谁是 powershell 开源免费的最大受益者? 答: powershell 可以运行在,win,mac,ubuntu1404+,centos7,debian8+,suse12+,arch,alpine linux,树莓派 Raspbian,win10-iot,docker,snap-app,open-wrt 路由器等。 这些系统使用者,是 powershell 开源免费的最大受益者。 问:powershell 完全开源了么? 答: 不完全是。 1 powershell 之所以简单、强大、好用。靠的是 powershell5.1+win 自带的 powershell 库。我们应该主要使用这些库。 这些库,并没有开源。开源之前,是否免费我也不清楚。 2 powershell6,powershell7,和相关的库,开源了。 这里面的区别主要是 [win 自带软件,相关的 powershell 库] 。 库数量很多,如 iis 的 ps 库。但这些 win 独有软件的 ps 库,跨不了平台。即便开源给 linux 也并没啥用。 另外一些 win,linux 通用的 ps 库,比如 sqlserver 的 powershell 库,已经开源免费放在了 github 和 powershell 画廊。 结论: 1 开源时间太短,社区力量不强。ps 开源库还没成气候。 2win 中的老旧不开源 ps 库挺好用。这些库中有价值的正在逐渐开源+跨平台。 3 不开源的 ps 库,如 iis 的 ps 库,hyperv 的 ps 库,还将继续存在,并作为 win 功能的一部分。 问:powershell 命令为啥那么长?我很不爽啊。 问:powershell 命令会重名吗? 答: powershell 命令太多,超过好几万。微软为了 powershell 命令不重名,所以把 powershell 命令搞的很长。 正因为命令长,命令唯一,才让 ps 基本不需要像 python 那样,在脚本中 import 这个库、那个包。也没有 py 那种 [库或依赖] 路径问题。 鱼与熊掌而已。唯一的长命令名,不需要学习记忆包名。 实际上 linux 命令也很长。有很多子命令。比如: kubectl expose deployment nginx --type=NodePort --name=example-service git reflog expire --expire=now --all 也有人说:“像 java 和 php 这种包名或者 namespace 又臭又长的” 实际上库多了,包名字都会长。 bash 不需要安装么? bash 是自带不需要装,但啥也干不了啊。你照样要东装一个包,西装一个包依赖软件。如: linux 上的 expect 这个工具,也需要装 tcl ! |
27
impl 2019-07-02 12:21:24 +08:00 via Android
shell 不够,python 来凑
|
28
q397064399 2019-07-02 12:24:25 +08:00
@impl #26 为啥不直接用 Python 可能我觉得脚本语法太古怪了 而且没找到好的调试工具
|
29
Imr 2019-07-02 12:27:45 +08:00 via iPhone
想法不错,支持一下。
虽然就像前面那位说的熟悉 bash 的人肯定不会用到这些,但是把脚本语言正正经经写出来,挺有趣的不是吗 |
30
Meltdown 2019-07-02 12:40:05 +08:00 via Android
有了这种库的帮助,100 行 bash 就可以做更多的事情了。当然如果为了性能着想,我会考虑换成其他语言。
|
31
xuboying 2019-07-02 12:56:33 +08:00
楼主的想法不错,不过当今 bash 确实不适合做复杂的事情了。
1. 现在流行的容器化封装 init 程序直接启动 app,绕过 shell 了包括 bash 2. 运维也可以用 ansible,复杂的任务可以交给 python 3. bash 的可靠性也不太行,set -eu -o pipefail 异常捕获在自己的 term 下执行 OK,上了 ci 系统就失效了。一直搞不清哪里出问题。有空还得换成别的更可靠的语言 |
34
ps1aniuge 2019-07-02 13:10:18 +08:00
大渣豪,我系渣渣辉,
我会写一篇为什么不用 shell 脚本人,为啥要用 powershell,而不用 python。敬请期待。 |
37
leopku 2019-07-02 14:11:17 +08:00 via iPhone
|
38
Geeker 2019-07-02 15:48:37 +08:00
这个很强啊,平时写点小脚本还挺实用
|
39
BruceAuyeung 2019-07-02 15:56:32 +08:00 via Android
很久之前我就有想搞一个这样的工具库,可是实在懒没干成,所以特地 star 支持下
|
40
james122333 2019-07-02 16:02:43 +08:00
这库才刚开始开发...
不过我写的不会公开就是了 参照我之前回复的 https://www.v2ex.com/t/570005 还可以这样搞 readonly true=1 readonly false=0 return() { case $1 in 0|true) echo true ; builtin return 0 ;; 1|false) echo false ; builtin return 1 ;; *) echo $1 ; builtin return $1 ;; esac } shell 可以处理复杂逻辑吗? 当然可以 至于好不好维护是看个人怎么写 |
41
jziwenchen 2019-07-02 16:08:59 +08:00
问下楼主 有没有 bash 学习的好资源推荐下?
|
42
james122333 2019-07-02 16:11:17 +08:00
把 builtin return $1 再加上判断是否数字会更好些 不是数字就不是状态了
|
43
adoyle OP @james122333 没看懂这个 return 函数有什么用。这是为了解决什么问题?
我是为了让 return 0/1 只用来区分命令是否有异常,用 true/false 来区分命令返回值的真与否,并且配合 `set -o errexit` 和 `shopt -s inherit_errexit` 这样的先决条件,才这样写的 is_ 函数的。 |
44
adoyle OP @jziwenchen 有的,Lobash README 里提到的 References 是一部分,
- https://github.com/dylanaraps/pure-bash-bible - https://www.gnu.org/software/bash/manual/ - http://mywiki.wooledge.org/BashFAQ 还有 - http://wiki.bash-hackers.org/ - https://kvz.io/blog/2013/11/21/bash-best-practices/ - https://github.com/learnbyexample/Command-line-text-processing 都是不错的文章 |
45
adoyle OP |
46
james122333 2019-07-02 19:58:01 +08:00
|
47
adoyle OP @james122333 大致了解了,想法很有创意,但是不符合我的需求。你看这段代码
https://gist.github.com/c52d778b9b01c183d0eb41aa16892177#file-t-bash 期望的是 is_success 返回 false,foo 收到后把结果打印出来,但执行会发现在 33 行就跳出程序了。 因为 `set -o errexit` 和 `shopt -s inherit_errexit` 起了作用。 `shopt -s inherit_errexit` 的目的是为了快速失败 (fast-fail),当 sub-shell 里抛异常了,那么当前 shell 也应该停下来而不是继续执行下去。所以 inherit_errexit 这个选项是必须的。 我为了区分异常控制流和普通的数据流,才因此用 return 0 表示命令正常,return 1 表示类似 throw error。用 echo true 表示数值为真,用 echo false 表示数值为假。 因此你说的 return 方式不符合我的需求。 |
48
james122333 2019-07-02 22:38:33 +08:00 1
@adoyle
你需要的是改变写法 hahaha 如以下 #!/bin/bash shopt -s extglob readonly true=1 readonly false=0 set -E trap 'case $err in false) ;; *) exit ;; esac' ERR return() { case $* in 0|true) err=true echo $err builtin return 0 ;; 1|false) err=false echo $err builtin return 1 ;; +([0-9])) err=$* echo $err builtin return $err ;; *) echo $* ;; esac } test() { return false } |
49
huiyifyj 2019-07-02 22:46:53 +08:00
bash 这玩意写不动大一点的功能,这样折腾会写着就很累,除非支持模块化(像 powershell 那样)。
|
50
james122333 2019-07-02 22:52:25 +08:00
|
52
iMusic 2019-07-02 23:21:30 +08:00
star
|
53
xiaolanger 2019-07-02 23:42:59 +08:00
写 bash 太累了,大佬厉害!还有,在服务器上升级 bash,基本与线上服务无缘了吧
|
54
adoyle OP @james122333 酷!利用 trap 真是巧妙的点子,感觉很有启发,可以改进 Lobash。感谢分享
|
55
adoyle OP @huiyifyj
> bash 这玩意写不动大一点的功能 你见过用 bash 写的 docker 吗? https://github.com/p8952/bocker 虽然是依赖了很多 linux 程序,15 年就停止更新了,但功能不算简单吧。 还有 Lobash 中使用的测试框架 [bats-core]( https://github.com/bats-core/bats-core) 也是纯 bash 编写,功能挺复杂的。 还有很多有意思的 shell 命令: https://github.com/alebcay/awesome-shell 能写出什么东西,一部分取决于语言的表达力,一部分取决于你的想象力。 > 这样折腾会写着就很累,除非支持模块化(像 powershell 那样) 通过唯一的命名空间来做模块化,Lobash 就是这么做的,Bash 脚本一般依赖不多的,可以人为控制避免命名冲突,虽然糙了点但能用啊。 然后,难道支持了模块化用了 powershell 就会不折腾么?每种方案都会伴随自身的局限,是否折腾要结合你的具体上下文来看。怎么避免就要靠你的聪明才智了。 |
56
adoyle OP @xiaolanger @hljjhb
想了一下,线上服务其实也能跑。Lobash 可以支持 4.2+。但数组相关的模块还有 sub/inc 模块一共 9 个模块无法使用,起码剩下 80+ 个模块是可以用的。 具体分析如下: Lobash 依赖 4.4 的 inherit_errexit 特性和 4.3 的 nameref 特性。 但在 4.4 出来之前,还是有很多用 Bash 写的脚本在线上跑也没出问题嘛。 所以 inherit_errexit 这个开关可以是个可选项(原本就是开发者自己选择去开的), 开启 inherit_errexit 是为了保证 fast-fail, 如果没开它,那就由开发者自己负责保证不触发异常情况(这本就是开发者应做的),多测试各种边界,那还是能在 4.3 上跑的。于是 Lobash 就可以兼容到 Bash 4.3+。 4.3 的 nameref 特性也不是所有模块都有用到,目前就数组相关的模块还有 sub/inc 模块一共 9 个模块有用到。 判断模块是否有用 nameref 特性的方法很简单,只要调用方式是传递变量名的,都是用到了 nameref 特性。 于是你只要使用剩下的模块,阉割了部分功能的 Lobash 就可以兼容 Bash 4.2+ 啦。 不过还需要你改下生成的 lobash.bash 里的 check_supported_bash_version 函数,把版本号检查改到 4.2,默认是 4.4。 我这线上 centos 都是 Bash 4.2,我想应该不会有更低的线上版本了。 |
57
ChristopherWu 2019-07-03 10:50:16 +08:00
题外话,我的经验: 凡是不能 3 分钟内写完的 bash 脚本,都特么用 python 写绝对没错。
你根本想象不了 bash 语法多难记,有多坑。 |
58
adoyle OP @ChristopherWu 题外话,可能你需要这个工具 https://github.com/koalaman/shellcheck
|
59
iyaozhen 2019-07-03 12:46:24 +08:00
@adoyle 我看了下我公司的服务器很多是 3.00.22(2)-release,最高是 version 4.1.17(2)-release
而且生产服务 bash 等组件是不能升级的。 我感觉楼主还是尽量向下兼容吧 |
60
adoyle OP @iyaozhen 好的,根据上面的说法,我觉得应该可以在少部分模块不可用的情况下支持到 4.0+,Bash 3 就饶了我吧,不想蹚这浑水。
|