V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  Jirajine  ›  全部回复第 72 页 / 共 213 页
回复总数  4245
1 ... 68  69  70  71  72  73  74  75  76  77 ... 213  
@wxf666 shell 的 变量 expansion 可以说是最糟糕的设计之一,一个变量的值,与如何引用它有关。而 IFS 就是控制如何引用变量的方式,所以非常易错。每当你引用含空格字符串的时候,都得设置 IFS ,包括变量赋值、复制等,操作其他字符串的时候还得再改回去。
elvish 在这方面和所有正常的编程语言一样:变量的值是固定的,不允许在引用变量时自定义各种奇奇怪怪的 evaluate 的方式,因而和 Python 等正常编程语言一样,evaluate 时不需要 quoting 。

elvish 不会更改你的变量内容,只是为了让使用传统*nix 命令行工具的 byte 输入输出格式更方便,很多接受多个 string 对象管道输入的命令(包括 (..) 输出捕获),也会接受 byte 流,并默认将 byte 流按换行符分割后作为多个 string 输入。其实这也是传统*nix 命令行工具约定俗成的格式,只不过 evlish 里真正有类型了而已。默认相当于 from-lines ,对于需要其他格式的输入则可以用 from-json (从 byte 流读取输入并反序列化 json 成结构化对象)、slurp (从 byte 流读取所有数据并存入一个 string 对象里输出)等等。
@wxf666 上下文敏感的 parser ,ls -al 是调用命令还是 算术表达式取决于上下文,这种不一致性在复杂情况下结果可想而知,变量名拼写错误会执行外部代码。

jq 就是糊字符串,简单读取一些 json field 倒还好,稍微复杂点的 group_by ,结构变换等就麻烦了,当然做肯定能做,毕竟 jq 自己也有一套“高级”的 dsl 。
脚本里有一大堆 ad-hoc 的 parse 和拼接字符串的代码,难写难读易错还不安全,远远不如直接操作结构化数据。

go/rust 的正则库都是从 RE2 来的,这种设计安全、高效、不会 overflow 、线性匹配时间,详见 https://swtch.com/~rsc/regexp/regexp1.html
Unicode script 和 lazy 匹配都是支持的,不支持的只有涉及 look around 和 backreference 的特性,完全不必要而且 overload 的字符更多让正则更难读。
quoting hell 指一次 evaluation 的结果再次被另一种相同或不同的规则 evaluate ,所以需要同时为多种规则 quoting 和转义。如:
ssh host touch 'my file.txt'
会创建 my 和 file.txt 两个文件。

bash 就是语言表达能力不足,才不得不把 glob 做的更复杂,另外涉及兼容性等原因有时开了有时又没开更加剧碎片化,zsh 在这方面更为尤甚。

这就是 IFS 和 word splitting 糟糕的地方,数据(变量值)影响语义,在代码的不同地方处理、存储、复制、传递含空格字符串,并保证结果正确是非常麻烦且恶心的。
bash 的 array 不是一般的难用,比如复制 array 到另一个变量:
a=('file 01.txt' 'file 02.txt')
b=$a
b=${a[*]} b="${a[*]}" b=${a[@]} b="${a[@]}"
b=( $a )
b=( ${a[*]} ) b=( "${a[*]}" ) b=( ${a[@]} )
以上这些 b 的值都是什么?
2022-09-06 08:00:52 +08:00
回复了 LnTrx 创建的主题 宽带症候群 IPv6 环境下一机多 IP 玩法的讨论
@cnbatch 操作系统当然支持,ipvlan 配合 netns 就可以做到。不过正常来说也不是完全必须隔离开,如果 host 上的程序都是你可控的话,直接给网卡加个 IP 然后让特定应用绑定,自行注意避免[::]就行了。
@zhoudaiyu 应该是使用 buildx 构建多平台镜像之前也需要设置好 bin_fmt 。所以你用了这个之后可以用 buildx 构建多平台镜像也可以直接基于 arm 的镜像正常构建。
可以用 https://github.com/multiarch/qemu-user-static ,然后直接基于 arm 镜像构建。
@wxf666 所以说它不是一个新语言,充其量只能算是类似 ipython 的 ui 。

结构化数据肯定只能在语言内部用,但 bash 是语言内部都没有结构化数据,你就得一直拿字符串糊过来糊过去。
ip --json addr | all (from-json) | each {|i| echo $i[ifname] $i[addr_info][0][local]}

正则搞得太“高级”,不符合 do one thing and do it well 的理念,这些功能自己写代码实现可读性和心智负担都更好,这也是 go/rust/cpp 等语言的正则库只实现一部分特性的原因。

quoting hell 了解一下,如果转义字符也需要转义。。

多打几个字符不代表复杂,看文档长度就知道哪个复杂了,elvish 可没有 extended glob ,特殊字符也很少。

word splitting 我举个最简单的例子:
一个目录里有两个文件:
Record.txt
Record 02.txt

a=$(ls) ; file $a # 这里是写$a 还是"$a"呢?
(我知道 ls 不该这样用,这里是演示处理含空格字符串)

日常使用结构化数据非常有用,尤其是数组,上面那个例子在 elvish 里就没有任何问题:
var a = (ls) ; file $a

word splitting 和 IFS 就是早年 sh 没有数组而发明的 trick 。

其他不需要 IFS 的语言怎么切割,这还用说吗?就像所有高级编程语言一样,用 str:split 函数啊。

另外 elvish 不会对结果做任何分割,是 (...)表达式本身可以 evaluate 成多个值,就像 golang 的多返回值一样。
@wxf666 parser 太随意,一部分传给 python ,一部分传给 bash ,语义严重不一致。

还是因为缺乏结构化数据类型,只能一边 parse 字符串,一边拼接出特定的字符串给别的程序 parse 。

go/rust 的正则库大差不差,功能完全够了吧,其他“高级特性”实现的话就做不到线性时间复杂度了,而且考虑可读性也不适合用单条正则写。

关键是它标准库有常用字符串和正则函数,这些 bash 根本实现不了。

一堆不同语言的转义,考虑的太多,glob 和正则共用不少符号但语义又不一样,增加心智负担。

elvish 的 glob 简单很多,从文档的长度上就能体现出来。

bash 几乎总是需要 quoting ,如果处理含空格字符串的话,空格有时候作为分隔符,有时候又不是,还有 IFS ,处理起来难写难用且易错。

bash 的数组和 map 那是在 posix sh 上后来加的,二等公民,而且不能表达结构化数据(数组存 map 、map 存数组),也避免不了 word splitting 的糟粕。

你那个命令 elvish 是兼容的,直接
apt purge (dpkg -l | grep '^rc' | awk '{ print $2}')
效果是一样的。
因为 elvish 兼容传统 byte pipe ,期望 chan string 作为输入类型的命令 也会接受字节流输入,并把字节流按换行符 split 。output capture 也会默认做这种转换。 如果不希望这种转换可以用 slurp ,slurp 接受读取 byte pipe 输入原样存入一个 string 里返回。
@aloxaf sed 的那个 script language 难道不是 dsl 吗?
@wxf666 这里说的是脚本,因为 Python 不是 shell ,调用命令即使使用 sh 这样库也不如 shell 直接。xonsh 就是个玩具,oil/osh 倒是一个类 Python 的 shell ,但 UI 比 elvish 差太多,而且是用一套自制工具链写的。

像你那个 rename ,用$1 $2 来引用 capture group 就是个自己的语言,这玩意不是 shell 变量,elvish 及其他高级编程语言都不需要多此一举,一致性更好。

用 shell 构建另一个语言的字符串,你得考虑 shell 的转义(单引号或$符号)、dsl 的转义( /符号)、正则特殊字符的转义,glob 又是一套类似正则,但又不同的匹配语言,太多不一致性和心智负担了。

word splitting 是因为 POSIX sh 一切皆 string ,缺乏 list 类型,导致 IFS 的 trick 和引用变量总是需要 quoting 。用 shell 处理包含空格的字符串简直是 nightmare 。

elvish 是支持结构化数据类型的,string 永远是 string ,不会被自动 split 也不需要 quoting 。你要传多个参数,直接用 list 就行了,subshell ( elvish 里是 output capture )可以像 golang 一样多返回值,只要输出多个值自然就是多个参数。
var a b = (put 1; put 2)
echo $a $b c 等价于 echo (put 1; put 2) c

bash 和 zsh 一样,也有一大堆晦涩的 expansion 语法,难记难写,不过 zsh 是最“强大”的,支持的功能最多,从 sh 到 bash 到 csh 再到 zsh 原创的,也是最混乱的。

elvish 也是崇尚简短的,你看内置函数的命名,一个单词或一个单词加一个介词,命名风格也没有需要 Shift 才能输入的符号,如 to-json 对比 PowerShell 里 ConvertTo-Json 。
2022-09-05 03:01:31 +08:00
回复了 systemcall 创建的主题 宽带症候群 ipv6 似乎被运营商收回了,有办法再要回来吗?
自己的配置问题吧,openwrt 直接用自动模式 option ipv6 'auto' 就行。
@wxf666 那个示例这样写便于阅读和复制粘贴,交互式输入把变量 inline 一下也只有一行。use re 是导入包,相当于 import 。
@wxf666 你上面的那种长正则,可读性很差的,不常写正则的人不用 regex101.com 这样的工具都看不懂。
rename 自己又发明了一种 dsl 语言,不熟悉的人用起来有额外的心智负担。而且你还得同时处理 shell/rename 自己的语言 /regex 的转义,再配上 glob 。

word splitting 可不是简短,是历史包袱,导致所有变量引用都得用引号括起来。
特殊语法如 man zshexpn 看一看,正常编程语言简单的字符串处理有多麻烦。

elvish 也是为交互式设计的,完全符合简短快捷易输入,PowerShell 才是故意搞得冗长、难以输入并美其名曰“可读性”的。
@wxf666 语法现代、没有 shell 那么多乱七八糟 word splitting 之类的糟粕,支持 namespace 。
支持 list/map 结构化数据类型,同时完美兼容传统的*nix 命令行工具和 byte pipe 。
顺不顺手,你直接看我上面写的,还有官网 elv.sh 上的示例,可读性比长串正则+特殊语法好的多,同时也不像 pwsh 那么冗长命名。
pwsh 就是个 dotnet script ,当 shell 实在是无比糟糕,命名冗长、过度 OOP ,外部命令是二等公民,管道完全不能用,只让你用 cmdlet 。
带 X 换成 '[^0-9X]'
用 elvish ,比 bash 顺手,也比 Python 方便:
put **.jpg | peach {|name|
use re
var number = (re:replace '[^0-9]' '' $name)
mv $name $number.jpg
}
peach 并发执行,换成 each 顺序执行。
2022-09-04 19:41:18 +08:00
回复了 nmap 创建的主题 程序员 现在招聘灰产开发都这么赤裸裸了?
@ch2 这些最多算违反协议、不正当竞争,企业被起诉罚款,怎么也轮不到吃牢饭
2022-09-04 19:27:30 +08:00
回复了 wwwtarzan 创建的主题 问与答 b 站账号被永封,是不是就没办法解封了?
@locoz 有这种想法说明你还没有训练完成,等你以后习惯了,你就会认为“审核人员的判断是绝对正确的” 或“审核人员既使偶尔有错误也是必要的、不可避免的、必须尊敬的、不应抱怨和诋毁的”,并感到自己以前觉得审核人员水平低的想法愚昧且无知.
1 ... 68  69  70  71  72  73  74  75  76  77 ... 213  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   729 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 38ms · UTC 20:10 · PVG 04:10 · LAX 13:10 · JFK 16:10
Developed with CodeLauncher
♥ Do have faith in what you're doing.