关于shell的一些图像

关于shell的一些图像

...以鸟哥的观点来看,多学一点总是好的,尤其我们可以有备而无患嘛。甚至学得不精也没有关系,了解概念也就OK,毕竟没有人要您一定要背这么多的内容,了解概念就很了不起。

<鸟哥的LINUX私房菜>

鸟哥是环境工程的博士,一点点靠兴趣从0啃下来Linux,写出了介绍Linux最有名的一本书... 阮一峰老师是经济学的博士,涉猎和兴趣也异常广泛,而且博客<阮一峰的网络日志>已经更新16年了,每次看到他们都很受触动..

解释器

解释器就是一个程序,写出来的程序语言必须被翻译成机器语言才能被计算机所理解。对于C++,Fortran这些静态语言,我们所谓的安装C++或者安装Fortran,实际上是安装它们的编译器,比如GCC系列的g++和gfortran,INTEL系列的icpc和ifort,编译器写好的文件编译成中间文件,连接程序ld再把生成的目标文件组合生成一个可执行文件. 这是静态语言的执行过程,这一整套从编译到连接的过程,起到了将字节码转换成二进制可执行文件的解释作用.

对于动态语言比如python,它并不是显式地执行编译、连接过程,最后运行一个可执行文件,而是由python解释器将源代码翻译转换成字节码,然后再通过python虚拟机将字节码转换成机器语言交给系统执行。因此安装python这个说法是有道理的,我们安装好在bin目录下的得到的python可执行文件python.exe实际上就是python的解释器,它本身是一个程序.

比如对于最常见的CPython来说,它的python.exe解释器是用C语言写的,解释器就是一个程序. 所以为什么python本身这么慢?只要用到了解释器,不论这句命令多么简单,它的运行逻辑都要远比编译好的静态语言复杂得多. 在python中即使int类型也有28个字节,它并不是一个真正的4字节的整数,而只是一个看起来像整数的C语言下的结构体,一个python中的整数类的对象. 因此要加速python速度,实际上就是直接接触其C代码,跳过解释器部分,有很多库的接口,可以比较简单地实现这个功能.

从这里也能理解为什么我们总是会对python作环境管理,比如最有名的Anaconda,而对c++这些很少谈,因为静态语言本身不存在什么版本..这是编译器的版本问题,这个问题引发的兼容性问题比较少. 而python有着无数版本的解释器,同时由于python有着太多的库,不同的库可能只支持特定某个版本的python解释器,同时库之间往往有着非常复杂的依赖关系,这种兼容性问题非常常见. python的开源特性,尤其是在科学计算或机器学习领域,这种发展迭代的迅速性又进一步加剧了兼容性的问题,包括python2和python3之间的过渡..等等. 手动控制多个环境,多个python版本几乎是一件不可能的事情,这也是为什么Anaconda包管理系统在python计算科学生态中如此流行的原因。

shell

shell也是一个解释器,和python解释器一样,它也就是一个程序. python解释器需要把python代码翻译成机器读懂的机器语言,shell需要把在Linux系统中我们输入的命令翻译出来交给系统内核(kernel)去执行,shell解释器有很多种,包括最常用的bash,以及sh,ash,csh,ksh等等,他们也都是一个程序而已。为什么叫它shell(壳),因为真正和系统硬件打交道的是系统内核,我们是在外层通过shell来使用操作系统,这就像是在核(kernel)外面的一层壳(shell)一样. 这些可执行的shell一般都在我们的Liunx服务器上的/bin目录下以及/usr/bin目录下.(/bin目录下一般储存着系统原生的一些指令,比如cat,cp等;/usr/bin目录下一般是系统提供的常用的应用程序的可执行程序,比如g++,make,python等等.)

我们知道python在使用时也是有两大类方法的,一种是交互式,

我们在命令行里键入python回车后,便进入到交互式环境中,解释器交互式地读取和执行命令. 当然也可以用python去运行脚本

依赖于解释器的脚本型语言都是类似的执行方式,在Liunx里运行shell解释器也是很类似的图像,我们只要登入Linux系统,就直接进入了交互式的shell环境,shell解释器交互式地读取和执行我们输入的命令,就像在python交互式环境中所发生的一样. 我们之前说过shell解释器有很多种,包括bash、sh等等,那么如何确定我们进入到的这个交互式环境中是哪一种解释器在帮我们翻译呢?

1
echo $0

这句命令会返回当前运行进程的名字,在交互式环境中运行这个命令,返回的就是当前运行的解释器的名字啦:

理解了上面的过程就可以更加清晰地认识到为什么要改变当前shell环境中的环境变量时要执行

1
source script.sh

而不是

1
./script.sh

因为我们所处的shell环境实际上就是一个shell解释器程序开启的一个进程,source命令会在当前进程下执行脚本,而./script会重新去运行解释器程序去执行脚本,就好像python xxxx.py一样,所以用后者运行脚本的方式肯定不会在当前交互式shell解释器环境中保存下来环境变量啦.

终端

终端窗口就是交互式环境所处的命令行界面,我们可以在里面输入命令,shell解释器去交互式地读取和执行命令. 比如我们在cmd中执行python进入交互式环境,这个交互式环境实际上是运行在这个cmd命令行窗口里的,这个窗口就叫终端.

我们登录到服务器,打开了一个终端窗口,我们在里面输入命令. 用户和计算机的这种临时交互称为一次会话(session). 一般来说,终端窗口和里面的进程是捆绑的,即终端窗口关掉了,这个会话也结束了,会话内部的进程也就终止了. 如果远程连接服务器在终端里运行一个进程,一旦网络断线,这次会话终止,那么这个进程也就消失了. 终端复用器就是实现了窗口与会话的解绑,窗口关闭时,会话并不终止,而是继续运行,等到以后需要的时候,再让会话绑定其他窗口(阮老师说得很清楚).

当然,在服务器里,我们一般不需要这么做,因为我们有集群调度系统已经做好了所有的事情,比如SLURM,PBS,LSF等等.