分享一个 Bash 脚本编程类库 Lobash

2019-07-02 09:35:00 +08:00
 adoyle

https://github.com/adoyle-h/lobash

看名字你或许猜到了,这是一个受到 JS 的 Lodash 启发的,专用于 Bash 编程的类库。

Bash 脚本的坑很多,我期望能写一个类库,把复杂的东西封装到简单的函数(模块)里,一个函数只做一件事情。以此来增强开发体验。

我已经写了 90 个模块,近 500 个单测,大致 API 和开发模式已经稳定。

我曾尝试想将 Lobash 支持 Zsh 的,搭完测试框架和环境,跑了一下测试发现,Zsh 和 Bash 还有很多不一样的地方。所以决定放弃支持 Zsh,可能哪天我会再写个 Lozsh 库。

我在自己的 Dotfiles 里试吃了自己的狗粮,没有遇到什么问题。所以来试用一下吧,有什么感想提 Issue 或在这个帖子里留言即可。提 Issue 请尽量用英文,用中文也可以。

如果觉得有意思,欢迎与我一起共建。
如果觉得不错,请点一下 Star,让我有动力继续开发,谢谢。

8286 次点击
所在节点    Linux
60 条回复
jziwenchen
2019-07-02 16:08:59 +08:00
问下楼主 有没有 bash 学习的好资源推荐下?
james122333
2019-07-02 16:11:17 +08:00
把 builtin return $1 再加上判断是否数字会更好些 不是数字就不是状态了
adoyle
2019-07-02 19:26:33 +08:00
@james122333 没看懂这个 return 函数有什么用。这是为了解决什么问题?

我是为了让 return 0/1 只用来区分命令是否有异常,用 true/false 来区分命令返回值的真与否,并且配合 `set -o errexit` 和 `shopt -s inherit_errexit` 这样的先决条件,才这样写的 is_ 函数的。
adoyle
2019-07-02 19:30:56 +08:00
adoyle
2019-07-02 19:34:10 +08:00
james122333
2019-07-02 19:58:01 +08:00
@adoyle
就是一起做阿 让 return 也拥有返回值的功能 并同时区分命令是否异常
builtin return $1 改判断会更好就是了 两种都可以写
adoyle
2019-07-02 20:41:50 +08:00
@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 方式不符合我的需求。
james122333
2019-07-02 22:38:33 +08:00
@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
}
fengyj
2019-07-02 22:46:53 +08:00
bash 这玩意写不动大一点的功能,这样折腾会写着就很累,除非支持模块化(像 powershell 那样)。
james122333
2019-07-02 22:52:25 +08:00
@huiyifyj

可以自己写模块阿 只是没什么现成的而已
我写了一堆 包括自动化的
Cyshall
2019-07-02 23:08:59 +08:00
@ps1aniuge 期待,能否麻烦到时候 @我一下。
MzM2ODkx
2019-07-02 23:21:30 +08:00
star
xiaolanger
2019-07-02 23:42:59 +08:00
写 bash 太累了,大佬厉害!还有,在服务器上升级 bash,基本与线上服务无缘了吧
adoyle
2019-07-03 09:04:21 +08:00
@james122333 酷!利用 trap 真是巧妙的点子,感觉很有启发,可以改进 Lobash。感谢分享
adoyle
2019-07-03 09:09:48 +08:00
@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 就会不折腾么?每种方案都会伴随自身的局限,是否折腾要结合你的具体上下文来看。怎么避免就要靠你的聪明才智了。
adoyle
2019-07-03 09:20:19 +08:00
@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,我想应该不会有更低的线上版本了。
ChristopherWu
2019-07-03 10:50:16 +08:00
题外话,我的经验: 凡是不能 3 分钟内写完的 bash 脚本,都特么用 python 写绝对没错。
你根本想象不了 bash 语法多难记,有多坑。
adoyle
2019-07-03 11:04:48 +08:00
@ChristopherWu 题外话,可能你需要这个工具 https://github.com/koalaman/shellcheck
iyaozhen
2019-07-03 12:46:24 +08:00
@adoyle 我看了下我公司的服务器很多是 3.00.22(2)-release,最高是 version 4.1.17(2)-release
而且生产服务 bash 等组件是不能升级的。
我感觉楼主还是尽量向下兼容吧
adoyle
2019-07-03 13:45:18 +08:00
@iyaozhen 好的,根据上面的说法,我觉得应该可以在少部分模块不可用的情况下支持到 4.0+,Bash 3 就饶了我吧,不想蹚这浑水。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/579173

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX