使用过Linux或是MacOS的程序员,都应该熟悉SHELL,而支持SHELL的其实有不同的实现,著名的比如Bash Shell以及Z Shell
而在Linux上,主流基本都是使用的Bash,但是MacOS这个操作系统却不太一样,最开始是Bash,后面在Catalina时,默认的又更换为Zsh,这又是怎么一回事呢?
还是先从SHELL的历史说起
对于Unix或Linux这样的操作系统来说,最核心的是内核,在内核之上就需要一个方式让解析用户输入的命令并能使用内核来执行用户的命令,而承担这个任务的东西,就是SHELL,用中文来翻译就是壳,你可以理解它是内核的一层外壳,我们是通过外壳来与内核进行交互的。
这就是SHELL。
但事实上,可能有一些程序员并不清楚的是,SHELL有非常多不同的实现,其实是挺多的。比如:
而在这些之中,bash广泛使用在Linux大多数操作系统中,而MacOS早期版本也是使用的Bash,但从Catalina开始,其默认的SHELL是Z shell,但同时保留了bash。
先说下为什么Linux大多使用的是Bash,其实Bash全称是Bourne Again shell ,它是对Bourne shell的重新实现。
为什么要重新实现呢?
因为Bourne shell是Unix系统的一部分,自由软件之父Richard Stallman在1983年开始发起了GNU运动,GNU运动的目标是实现一个免费自由的操作系统,以解决Unix系统的License问题。
要做一个类似的UNIX系统,理所当然的Unix上有的,都得自己重新实现一套,因为Unix上的东西都是有版权限制的,自然对于SHELL也是如此。
Unix上的Shell是Bourne shell,于是GNU也做了一个Shell,名称就是Bourne Again shell,简称Bash。
而Linux之父在1991年发布的Linux内核中,最开始只有两个程序,一个是GCC,另一个则是Bash了,它们都是GNU软件。
至于后面发展起来的Linux操作系统,我在以前的文章中也说过了,其实就是Linux内核 + GNU软件,所以Linux操作系统也叫GNU/Linux操作系统。
这就是为什么Linux发行版本中,大多使用的是Bash的原因了。很容易理解了吧。
再来说下Zsh,Zsh其实是对Bash的扩展,它基于Bash之上添加了很多新特性,它包括了Bash,Ksh以及tsch的一些特性的集合。
所以Zsh可以说是更好的Shell,但由于Linux上述讲述的历史原因,大多数Linux发行版本仍然是用的Bash,而MacOS一开始用的也是Bash。
但MacOS用的Bash的版本一直是非常陈旧的(MacOS使用的一直是Bash 3.2,而Bash最新已经到5了),以至于到了Catalina时,干脆弃用Bash,而转而选择Zsh做为默认的Shell环境。
而之所以这样做的原因只有一个,那就是版权限制
Bash在版本3.2之前,它的开源协议用的是:GPLv2,而之后的Bash版本就将其协议修改为GPLv3了。
GPLv3是GPLv2的改进版本,它解决了GPLv2的一些缺点与不足,其中一个重要的点就是,扩大了GPL强制传染力的约束。
也就是如果你的产品使用了GPLv3的类库或框架,你的产品不管是否包含独立可区分的部分,也一定也同样的按照GPLv3协议进行开源。(GPLv2时,使用了GPLv2的产品,如果包含可区分的独立部分,非全部派生自开源软件,则可以不受GPL传染力约束)
可想而知,这不是Apple希望看到的结果,这也是苹果长久时间一直使用的Bash 3.2的原因所在。使用Bash 3.2的MacOS仍然可以不用开源,但如果使用GPLv3的话,则MacOS也一定得开源了。
但是如果一直使用一个相当陈旧的Bash版本,对MacOS操作系统并不是一个合适的选择,于是Apple在MacOS Catalina后,选择了将Shell迁移至开源协议更友好的Zsh。
Zsh使用的是MIT开源协议,MIT完全不限制商业使用,当然是Apple更喜欢的选择了。
事实上,无论是Unix或是Linux,还是MacOS,都存在 /bin/sh
从名称上来说,你可能以为它是sh,但事实上,如上述我说的这些历史及原因,这个文件大多是兼容考虑而继续存在(因为最开始就是用的/bin/sh),而在不同的操作系统上,/bin/sh其实是链接到不同的SHELL实现。
比如在Debian上,输入以下命令
$ ls -all /bin/sh
## 结果是
lrwxrwxrwx 1 root root 4 12月 10 2020 /bin/sh -> dash
这说明,实质上/bin/sh只是/bin/dash的软链接而已。
而在MacOS的系统中,存在以下不同的shell
是不是感觉非常多,那到底默认的是哪一个?
#查找系统中默认的SHELL
/usr/bin/env | grep SHELL=
#MacOS 12.4的结果是
SHELL=/bin/zsh
这说明默认的SHELL是/bin/zsh
而在SHELL脚本中,第一行一定是申明你要用哪个SHELL
#!/bin/sh
echo "这是一个SHELL脚本,我用的是/bin/sh,它可能是另一个shell的软链"
通常情况下,我们都是使用/bin/sh,因为它是所有系统中都基本是存在的。而/bin/zsh这样的,不一定会存在。
如果脚本是专门为Linux准备的,那使用/bin/bash可能也是比较多的选择,因为几乎所有Linux中一定会有/bin/bash的。
至于不同的SHELL,在语法及功能上是存在一些差别的,这就是你要编写脚本时,你要另外去了解的一件事情了。
我是御剑,一个致力于追求,实践与传播编码之道的程序员。
访问微言码道
(https://taoofcoding.tech)以阅读更多我写的文章;
访问myddd
(https://myddd.org)以了解我在维护的全栈式领域驱动开源框架。