2019年11月公告:

(1)《趣谈Shell》由MyBatis中文官网站长原创编写,仅供个人学习使用,不得用于任何商业用途,不得用于公司内部员工培训,不得用于培训机构学员的教学!请认准MyBatis中文官网,网址:www.mybatis.cn

(2)站长其人,低调专注,历任网易高级大数据开发工程师,技术专家,盈利千万级别公司CTO等职位,欢迎热情人士提出指正建议。

(3)MyBatis中文官网专注于分享、交流和研究的非营利性组织,当前有3000+社群成员。《系统化学习的数学模型》、《趣谈Shell》均属于MyBatis中文网的研究成果。

寄语:

这是一个传说,亦真亦幻;

这是一个故事,有你有我;

平凡孕育着伟大,伟大归寂于平淡;

这就是《趣谈shell》。

《趣谈Shell》解决的问题

一本好书应该是让读者怀着一颗好奇心去思考知识背后的东西、发现知识之间的联系。但是,大多的书注重内容的收录,忽视思维过程的展示,如下面这些书。


shell命令比较多,而且又零碎,所以很难学习,下功夫去记忆书上的命令,记住这些命令的参数,这样做看似学会了,其实两手空空。

一个单词好记,十个单词也好记,但是一百个单词,一千个单词往往会让你抓狂。道理一样,一个命令简单,十个命令也简单,但是在一百个命令面前,你还觉得shell简单,我会拍着你的肩膀说:兄弟,说实话,别吹牛。

简单与复杂,往往与数量有关,再简单的东西,一旦量大了,它也会变得复杂。

《趣谈Shell》解决的问题就是把复杂的事情变简单,解决的措施是降维。

把大量变成少量,需要找联系。命令与生活的联系,命令与命令之间的联系,只要找到内在联系,两个命令、三个命令、五个命令往往结合成一块儿东西。不仅量变少了,命令还能学活,有左右逢源的灵气。

《趣谈Shell》成书历史与售价

《趣谈Shell》,从2018年10月26日开始编写,截止2019年10月26日,历时一年的时间,总计40小节。

《趣谈Shell》的价格情况:原价:65元,并提供为期一个月的学习指导。

备注1:《趣谈Shell》无实体书,所有内容全部在特定网站存放,便于随时修订。

备注2:有人建议,可以在双十一期间,对《趣谈shell》做一次优惠活动,建议售价9.9元左右,毕竟60多元的价格说低不低,一本《深入理解计算机系统》700多页的经典教科书,双十一也才60多。作者回复:让那些写9.9左右的人也写一下,他们要是能超越我的《趣谈shell》,我倒贴钱给读者。再者,入门简单,深入很难。趣谈shell的定位就是入门和深入,我不觉得当前这个定价高,而是认为它是物超所值的。

《趣谈Shell》的用户好评

以下评价均来自用户的真实反馈,不再抓截图了,也不再记录用户名,只记录用户好评的时间和内容。

2019年10月23日,用户反馈:

写的挺好的,跟看小说一样

2019年10月25日,用户反馈:

我终于明白什么才是真正的知识体系了,就是由点到面再到空间的过程,我们很多人学东西学的其实都是点,可能连线都没有连接上,更不要说面了,所以我觉得学习应该是当你有足够的点时连接成面,再通过这一面去扩展其他面,这就是知识体系。很多大牛都经常说知识是相似的应该就是这个道理。当你有自己的空间自己的知识体系以后,再学习其他东西,无非就是把自己已有的知识和新的知识连接起来,扩大自己的面。

我又回头看了一遍文章发现这已经不只是再讲简单的shell了,仔细一想发现有些文章涉及的信息量很大。

站长能把这个知识体系讲明白真的佩服佩服。

2019年11月1日,用户反馈:

群主的小册子 我看了,确实可以。就是太高深了

2019年11月1日,用户反馈:

站长,能不能再解释一下Context?我最近看的Hadoop,和Spark的源码都会有HadoopContext,SparkContext的代码。

OK,看到了,看来值得一买来仔细研究

用户购买记录

1、姓名:王~飞,付费时间:2019年09月21日

2、姓名:吴~想,付费时间:2019年09月21日

3、姓名:王~磊,付费时间:2019年09月24日

4、姓名:于~, 付费时间:2019年09月25日

5、姓名:李~鹏,付费时间:2019年10月09日

6、姓名:陈~, 付费时间:2019年10月11日

7、姓名:刘~, 付费时间:2019年10月11日

8、姓名:黄~, 付费时间:2019年11月05日

9、姓名:赵~冬, 付费时间:2019年11月08日

10、姓名:王~杰, 付费时间:2019年11月08日

11、姓名:刘~庭, 付费时间:2019年11月10日

节选一:三国鼎立,江湖恩怨

有人的地方,既有江湖,必分门派。不仅人类的社会发展进程如此,科技的发展皆是如此。

在西方极乐世界,先后涌现出三大帮派。

第一个帮派是Unix,这是由一群科学家建立的。科学家思想单纯,一门心思搞科研,然后转换成果来变现,所以Unix是一个商业化的产品。

第二大帮派是GNU,其老大精力充沛,充满理想主义色彩,只因为看不惯唯利是图的Unix,就想创建一套完全自由、免费的操作系统。这个老大采用的战略是:农村包围城市。在老大的带领下,此帮派开发了很多周围的产品,比如功能强大的文字编辑器Emacs,再如性能强悍的C语言编译器GCC等等,但是老大时运不济,一直打游击战,从没有占领过核心城市,自始至终都没有做出自己的操作系统,甚是可惜啊。

第三大帮派是Linux内核,这个门派的老大性格孤僻,但是眼光独到,只做内核,做的风生水起。树大了自然会开枝散叶,引起百鸟前来筑巢,GNU组织的大量自由软件都纷纷过来占位,门庭如市,车水马龙,好不热闹。

一年又一年过去了,GNU的操作系统一直没有做出来,而自己的手下和门徒都跑Linux内核组织了,GNU门派的老大有点坐不住了,黑着脸找上门,告诉Linux内核的老大,以后不能再叫“Linux”,应该叫“GNU/Linux”,毕竟拿人手短,Linux内核组织的老大也不好说什么。不过,世人的习惯难改啊,有的叫Linux,有人称GNU/Linux,一直这么延续着,反正都是一回事。

节选二:精灵小黑,分身有术

打开shell,出现一个黑色的窗口,即是小黑,它是shell进程。

小黑是个精灵,是个活生生的精灵。你可以给小黑打个招呼:echo Hello,小黑给你一个回复:Hello。如下所示:

		 [root@localhost ~]# echo Hello

[root@localhost ~]# Hello
		 
		 

最神奇的地方在于:小黑还可以诞生出一个小小黑,你可以执行:sh xxx.sh,这个时候就会诞生出一个小小黑。至于它是不是黑的,不好说,但是可以肯定的说,它是小黑诞生的。准确的叫法是:子进程。

只要在小黑面前执行sh xxx.sh命令或者./xxx.sh,小黑就会诞生出一个小小黑,既然这么容易分身,那么就有人开始担心了:我在小黑那里存放的东西,小小黑是否知道呢?

确切的说,在小黑那里存放的东西,小小黑是不知道的。用户存放的东西,叫用户变量,只在当前小黑中可见,小小黑是看不见的。要想让小小黑也能看到用户存放的东西,必须设置为导出,也就是export。天知道小黑能诞生出多少个小小黑呢,所以凡是用export设置的变量都称为环境变量。

小黑的东西,小小黑是看不到的,那问题来了,小小黑的东西,小黑能看到吗?答案是:不能的。那如果有人想让小小黑给小黑传话,怎么破?不能破啊,干嘛非得多此一举呢,直接跟小黑对话吧,越过小小黑,用source的方式,也就是source xxx.sh的方式,这个时候就不会再平白无故冒出个小小黑了。

后记:解决变量的可见与可用两大难题,Export和Context联袂出手,枯木又逢春

从文中提到的:父进程->子进程,用户变量->export->环境变量。解决了变量的可见性问题。下一个问题就是可用性,如何在子进程中获取到环境变量呢?我联想到了Context,这个时候该Context出手了,此乃“上下文”之意,是给“变量”创造”环境”。所有的环境变量集聚到一起,这种集合就叫上下文。

我们知道,程序是由各种模块组成,一个模块的正常运行,除了自身内部变量参与其中,还需要召唤其他模块的外部变量,共同协作。去哪里召唤这些外部变量呢?从Context里面获取即可。

在编码世界中,Context的编码手法无处不在:

(1)在Tomcat里面,每一个Tomcat上下文都表示一个Web应用。

(2)在Spring里面,有两个核心接口:BeanFactory和ApplicationContext。

(3)在MyBatis里面,有ErrorContext,记录本次执行过程中异常的上下文信息。

(4)在Android里面,Context是个抽象类,是其他三个重要类(Activity、Service、Application)的父类。

(5)在HttpClient里面,有HttpContext,表示HTTP的上下文执行环境。

(6)在kafka里面,有LogContext,顾名其意,用于log的执行环境。

(7)……

在IT世界中,Context的编码手法无处不在,可以说,有程序的地方必有Context。

当你的代码,写的繁琐无味,死气沉沉,如白开水一般平淡,你可祭出Context手法,我相信,必能枯木逢春,让腐朽的代码充满生机。

节选三:两套领导班子,以备不时之需

明朝视南京为陪都,拥有一样的领导班子,以备不时之需。同样道理,GUN/Linux也有伪文件系统,可以从用户空间读取内核空间的系统参数。

我们知道,内存分为两部分,一部分被用户占用,一部分被操作系统占用,这个道理学过计算机的人都知道。

但是,内存这个概念太土了,科学家们聚到一起开会的时候,总不能你一句内存,我一句内存的讨论问题吧,这不是成了电脑维修了。为了显示清高,科学家们随后就想了一个更高大上的字眼:空间。人类的世界就是由空间和时间构成的,而在计算机世界里面,也有了“空间”之说,立马是不是觉得变得高大上了呢。

科学家又将空间分为内核空间和用户空间。虽然内核空间,用户空间这些术语让人有点发蒙。空间的本质就是内存。一堆符号叫程序;跑起来之后叫进程;内存条插入主板,跑上程序,就变成了空间,被操作系统占用的叫内核空间,被用户进程占用的叫用户空间。

两个空间是独立的,操作系统只能读写自己的空间。用户的程序跑起来,它总不能跑过去玩个躲猫猫吧。同样道理,用户的程序跑起来,它总不能跑到操作系统空间尿上一泡吧。天有仙庭,地有人间,用户程序不是孙悟空,不能上天入海,上蹿下跳,只能待在自己的地盘。

伪文件系统的存在,便于从用户空间读取内核空间的系统参数。其实,每个运行的进程都在/proc中拥有一个对应的目录,目录的名称与进程ID相同。以小黑为例,它的id假如为4567,则存在对应的/proc/4567目录,目录里面包含了大量的信息,甚至还有很多敏感信息。有人会在小黑那里存放东西,都可以查看到的:cat /proc/4567/environ,显示了所有传递给小黑的环境变量。

节选四:一战(栈)成名

很多聪明人会发明一些聪明的工具,但是却秘不示人,只在与人对决中,亮出杀手锏,一战成名。至于对手嘛,连自己是怎么死的,都往往不清楚。

历史上这样的例子比比皆是,例如大名鼎鼎的牛顿,早就发明了微积分,但是一直没有公布研究成果,暗中利用微积分解决了跑上门来的各种挑战。

在上古时期,都是机械化,手动化的解决问题,人们通过cd命令来切换一个又一个目录,这种手动输入路径,在多个文件中切换是一件非常麻烦的事情。后来,一个聪明人发明了一个新的工具,一下子就破解了这个难题,这个工具就是:栈。使用pushd和popd的时候,完全可以无视cd命令。栈的用法如下:

(1)$pushd /var/www,切换当前目录到/var/www,并将/var/www压入栈

(2)$pushd /usr/local,切换当前目录到/usr/local,并将/usr/local压入栈

(3)dirs,用于查看栈里面的内容,此时显示为:/usr/local /var/www ~,栈里面的内容存放是有序的:/usr/local为0,/var/www为1,~为2

(4)pushd +1,表示切换到栈中1的目录,也就是:/var/www,此时dirs一下查看栈的内容,则变为:/var/www ~ /usr/local

(5)popd +2,删除2位置,此时栈内的内容变为:/var/www ~

聪明人与普通人的对决中,普通人使用cd手动切换目录,而聪明人使用栈,效率极快,从而一战(栈)成名。

节选五:大道至简

一门开发语言,往往有两大部分做成:变量赋值,逻辑运算。而shell在这两个方面做到了极简:

(1)变量赋值的极简做法,中间不能有空格,真正做到了极简:

变量的赋值形式是:var=value,而var = value,则表示相等

(2)逻辑运算的极简做法,连if都可以省略掉:

		 [ condition ] && action; # 如果condition条件为真,则执行action

[ condition ] || action; # 如果condition条件为假,则执行action
		 
		 

最厉害的是这个写法:命令1 && 命令2 || 命令3: 当命令1成功时会执行命令2, 当命令1失败时,会执行命令3

其实,shell的极简思想无处不在:

(1)每个变量的值都是字符串,无论赋值的时候是否添加引号,值都是以字符串的形式存储的。

(2)字符串的比较形式是双中括号[[ ]]。判断是否是空字符串,则用:[[ -z $var ]],判断非空,则用[[ -n $var ]]

(3)变量虽然是字符串存储,但是依然可以进行算数比较:[$var1 -gt 0 -a $var2 -lt 10],表示: $var1 > 0 and $var2 < 10

(4)变量虽然是字符串存储,但是依然可以当做文件来进行检测:[ -e $var ],表示变量包含的文件是否存在。

总之,一个字符串存储的变量可以代替三种类型:字符串类型,数值类型,文件类型。

节选六:xargs的左右逢源

顺水人情,指的是利用机会顺便给人好处,管道命令|就喜欢干这事。但是偏偏有人不领情,那管道命令就傻眼了。

书接上文,我们知道很多命令都喜欢胡吃海喝,但是有的命令却不喜欢从键盘上捡食儿,看看这位:

echo '4567' | kill

kill大佬就不处理标准输入的,管道命令傻眼了吧,这个时候只能求助于xargs了,xargs可是一个左右逢源的好手。它不会像管道那样,赤裸裸的把好处送到人门前,它会偷偷摸摸的从后院进去,放到命令行参数位置,神不知鬼不觉的就把事情办妥当了,就像这样:

echo '4567' | xargs kill ,等同于:kill 4567,大家看到没,东西放到后院了吧?

再来体会一下,xargs的妙用吧:

		 echo '--help' | cat 

#输出:--help

echo '--help' | xargs cat

#输出:Usage: cat [OPTION]... [FILE]...
		 
		 

其实,xargs做事非常细致,大件礼品会分成小份,掩人耳目:默认情况下xargs将其标准输入中的内容以空白(包括空格、Tab、回车换行等)分割成多个之后,当作命令行参数传递给其后面的命令,可以使用 -d 命令指定分隔符,例如:

		 echo 'www.shelltalk.cn' | xargs -d '.' echo 

#输出:www shell talk
		 
		 
节选七:海象运算符

在《大道至简》小节中提到了:看似小小的字符串变量,却能随机应变,化身丰富,时而以原身(字符串类型)的形式出现,时而化身数值类型,时而又化身文件类型。本节再来看看字符串的替换和删除。先看看替换的语法规范:

website=shelltalk
echo ${website/shell/thread}

用/隔开就行,而/也被用于根目录。知道了替换的用法,也就能举一反三,联想到删除的做法:

website=shelltalk
echo ${website/shell}

替换和删除的前提条件是字符串不能为空。如果字符串为空,则需要增加默认值,这种情况下怎么办呢?不同的语言,有不同的规范。在freemarker中是这样处理的:unsafe_expr!default_expr,例如:${website!"shelltalk"} ,而在shell中是这样处理的,更显得有意思:

website=
echo ${website:=shelltalk}

:=符号的含义是将值赋给一个变量。它被亲切地称为“海象运算符”(walrus operator),因为它长得像海象的眼睛和象牙。


联系方式:

MyBatis中文官网@2019年11月