Shell与kernel
作者:大宽宽
链接:https://www.zhihu.com/question/35382632/answer/803711006
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
shell是什么?
操作系统对外提供的接口是“系统调用”,也就是一堆编程用的接口。这些接口一般以C函数的形式暴露给使用者。通过这些接口,开发者可以命令操作系统“启动一个进程”,“查找某个目录下的所有文件”,“将某个文件的权限配置为744”等等。
实际上我们平时编程用的是对系统调用的包装,比如libc里的那些库函数。但无论如何,你总是得写代码才能使用它们。
问题是我们平时使用电脑,不能每次都编写程序,再编译,再运行得到结果吧。比如你想知道一个目录下的所有文件,你肯定不会去写一段C代码,调用系统调用“readdir” (见http://www.man7.org/linux/man-pages/man3/readdir.3.html),然后gcc编译,然后运行。真这么干,一个最简单的工作也要耗费很长时间。况且,一个函数的返回是“数据结构”,或者输出到stdout或文件之类的地方。你总得以某种形式把结果“画”到界面上(不管是画字符还是画图片),才能查看那个结果。这个格式化输出的工作量也很大。
正常人的思路是先写好程序,然后弄个交互的界面方便使用这个程序。只要使用者敲一组字符串,就可以调用之前写好的程序完成工作。比如我们会在命令行里输入“ls -Rl”这种字符串。这个字符串被翻译成“ls”,“-R”,“-l”。“ls”帮我们找到那个之前写好的程序,并启动它;“-R”和“-l”被作为参数传给这个程序,告诉程序走“递归所有子目录”+“输出长格式”这部分代码。
这个负责把用户输入的字符串转换到需要执行的程序,并把结果以某个形式画出来的东西,就叫做“Shell”,即帮你更方便使用操作系统接口的“壳”。这个词与操作系统内核(Kernel)对应。
在Linux中,bash负责按照某种格式把用户的输出的字符串翻译,比如对于普通非空字符翻译为程序和参数,并尝试去PATH里找对应的程序。例如
- 对“空格”翻译成分隔符;
- 对“$XXX”尝试进行环境变量的替换;
- 对“|”翻译为管道;
- 对 “>”翻译为输出重定向;
- 对一个指令末尾的“&”翻译为将程序转到后台执行……
更多Special Characters and Quoting for shell
另一方面终端将stdout、stderr输出的东西画成我们可以看的一坨坨字符,包括字符、字体、颜色、换行、甚至响铃。
【bash】 + 【终端】大概可以理解为一个以字符为交互方式的“Shell”。
当然,大家会更习惯上说“bash”是一个“Shell”。也许是因为bash大家用的不爽可以换,可以改变配置,可以编程。总之玩法很多。但是对终端一般不怎么理会,默认的就够用了。或者也可以理解为“终端“属于操作系统的一部分。不管如何,可以习惯这些不同角度的不同看法,不需要特别细纠,理解大概意思就好。
除了bash,还有像csh,zsh等,虽然各自的规定有些区别,但干的事情就是这些。Windows里一般等价的就是cmd,与Linux这边相比弱鸡得很。不过Windows有自己的PowerShell,也可以通过cygwin或者linux subsystem的方式使用bash。
如果你自己定义一个解析字符串的“Shell”,你可以规定用分号而不是空格做分隔符;用#而不是$代表变量……
Shell也可以做成图形界面的,比如你点击一个窗口里左边的一个目录图标,右边就展示这个目录下的所有文件。他做的事情和上面ls一模一样,只不过接受的是点击,而不是输入字符串;输出的是一幅画,而不是格式化的文本而已。内部还是转换成调用系统调用来完成工作。
如果你开心,你甚至都把Shell可以做成声控的,比如你说一段语音,你的“Shell”识别后翻译为调用程序的指令,执行成功后就可以把结果翻译为语音再返回给你。你一定熟悉“小爱同学”,“Hi Siri”这种东西吧。
Shell的思想很普遍,并不一定限制在操作系统上。比如你自己写一个程序,有大量复杂的参数和配置。为了使用方便可以写个命令行工具将一个命令翻译成对这段程序的调用。你写的命令行工具就是你自己程序的“Shell”。比如写Java的同学肯定很熟悉mvn。一句mvn install可以产生出成百上千个下载、压缩、编译、清理、测试、上传等api的调用;使用数据库的同学也会用SQL来表达自己的查询,让数据库的“Shell”解释成对存储引擎各种api的调用。
怎么check你用哪个shell?
echo $0 # gives you the current shell
echo $SHELL # gives you the default shell