初识 Shell
![](http://img.blog.itpub.net/blog/attachment/201803/8/31391681_1520524139CmH9.png?x-oss-process=style/bb)
上图是一个完整的、可执行的 Linux Shell 程序,使用上述第一种方法运行此程序,结果如下:
可以看出,当前目录并未被程序中的代码改变。
当命令行 shell 执行程序时,首先判断程序是否具有执行权限,然后调用 Linux 内核命令新建(fork)一个进程,在新建的进程中调用指定的命令,如果程序文件是编译型(为禁止文件),则 Linux 内核知道如何执行。但是,上图中的 echo.sh 程序文件是文本文件,内核不知道如何执行。于是内核返回“not executable format file”(不是可执行的文件类型),当 shell 收到这个消息时,则判定此文件是一个脚本。
当 shell 判定此文件为脚本后,启动一个新的 shell 执行它。但是现在的 Linux 系统一般都有好几个 shell,通过脚本的第一行“#!”告诉运行 shell 创建一个相应的进程来执行脚本。
![](http://img.blog.itpub.net/blog/attachment/201803/8/31391681_1520524268qOGA.png?x-oss-process=style/bb)
当命令行 shell 执行程序时,首先判断程序是否具有执行权限,然后调用 Linux 内核命令新建(fork)一个进程,在新建的进程中调用指定的命令,如果程序文件是编译型(为禁止文件),则 Linux 内核知道如何执行。但是,上图中的 echo.sh 程序文件是文本文件,内核不知道如何执行。于是内核返回“not executable format file”(不是可执行的文件类型),当 shell 收到这个消息时,则判定此文件是一个脚本。
当 shell 判定此文件为脚本后,启动一个新的 shell 执行它。但是现在的 Linux 系统一般都有好几个 shell,通过脚本的第一行“#!”告诉运行 shell 创建一个相应的进程来执行脚本。
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_1520526052pElH.png?x-oss-process=style/bb)
上图就是运行 shell 程序的第二种方法:调用命令解释器执行脚本。
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_15205282767ttv.png?x-oss-process=style/bb)
上图是运行 shell 程序的第三种方法:直接使用 source 命令(也被称为点命令)执行脚本。
Linux Shell 可执行的命令有三种:内建命令、shell 函数和外部命令。
内建命令就是 shell 程序本身包含的命令,这些命令集成在 shell 解释器中,例如 cd、echo 等。在执行内建命令时,没有进程的创建和消亡。
shell 函数是一系列程序代码,以 shell 语言写成,可以像其他命令一样被引用。
外部命令是独立于 shell 的可执行程序,例如 find、grep、echo.sh。命令行 shell 在执行外部命令时,会创建一个当前 shell 的复制进程来执行,因此存在进程的创建和消亡。执行过程如下:
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_1520527488f45o.png?x-oss-process=style/bb)
子进程在创建初期和父进程一模一样,但是它不能改变父进程的参数变量。只有内建命令才能改变环境变量。
通过上面的解释,在使用前两种方法执行 shell 脚本时,执行过程如下:父进程接收到命令“./echo.sh”或“/bin/bash echo.sh”时,发现不是内建命令,于是创建了一个和自己一模一样的子进程来执行这个外部命令;子进程用 /bin/sh 取代自己,sh 进程设置自己的运行环境变量;sh 进程依次执行内建命令 cd 和 echo,环境变量被改变,但是父进程的环境变量并没有受到改变;sh 子进程执行完毕,消亡。父进程从等待状态醒来继续接收命令。
而使用 source 命令执行 shell 脚本时,没有子进程的创建与消亡,而是直接在父进程中执行。
变量(variable)实际上是一个键值对,例如 str="Hello",就是将字符串值(value)“Hello”赋予键(key)str。在 str 的使用范围内,都可以使用 str 来引用“Hello”值,这个操作叫做变量替换。Shell 中的变量名称以一个字母或下划线开始,后面接任意长度的字母、数字或下划线。而且它对变量类型不做区分,一切值都是字符串,键值都没有长度的限制,但是在值为数字的时候,bash 是允许进行比较操作和整数操作的。键值对赋值的时候,等号两边不能有任何的空格,想要使用变量名称获取值,需要使用 $ 符号,当赋值的内容包含空格时,需要加上引号。
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_1520559840C62W.png?x-oss-process=style/bb)
需要注意的时,使用 $ 符号获取变量值的时候,只是 ${with_space} 的简写形式,在某些上下文中,使用 $with_space 可能会引起错误,这时就需要使用完全形式了。当变量没有 $ 前缀出现的时候,可能是如下几种情况:变量被声明或赋值、变量被 unset、变量被 export。
变量赋值可以使用等号,也可以在 read 命令中或者循环头进行赋值,例如 for var in 1 2 3。被双引号括起来的变量替换是不会被阻止的,因此它被称为部分引用或弱引用,而使用单引号将会禁止变量替换,变量名只会被解释成字面的意思,因此单引号被称为全引用或强引用。在 shell 中,变量值可以是空值(NULL),这很常见且合理,但是在算术运算中,空值变量往往被看作 0,不过这是一个为文档化(同时可能是不可移植)的行为。
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_15205608311DT0.png?x-oss-process=style/bb)
Linux Shell 中变量类型有两种:局部变量可见范围在代码块或函数中,并且必须明确以 local 声明,否作它是全局可见的;全局变量(例如环境变量)可见范围为全局,不需要加任何修饰词。
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_1520577552t0l4.png?x-oss-process=style/bb)
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_1520577566FFpO.png?x-oss-process=style/bb)
echo 命令通常用来将各个参数打印到标准输出。参数间以一个空格隔开,在输出打印结束后,换行。下图为它的转义字符序列。
![](http://img.blog.itpub.net/blog/attachment/201803/9/31391681_1520579363G52Q.png?x-oss-process=style/bb)
env 命令不带参数的情况下,显示所有环境变量,-i 参数表示不带环境变量,-u 参数表示从环境变量中删除一个变量。(与 set 函数显示所有本地变量不同,env 函数只显示环境变量)
unset 命令默认为删除变量(-v 参数),如果使用 -f 参数,则被视为删除函数。
语言类型:计算机内核(CPU)不能直接理解高级语言(Linux Shell、Java、Python 等),只能直接理解机器语言,所以必须把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序。
翻译的方式有两种:一个是编译(compile),一个是解释(interpret),这两种方式只是翻译的时间不同。编译型语言在执行程序之前,需要一个专门的编译过程,把程序编译成机器语言的文件,在之后的运行中,就不用重新翻译了。解释性语言不需要编译,只是在程序运行的同时进行翻译,通常会有一个专门的解释器(
例如 Linux Shell 中的
/bin/sh、bash、zsh、csh 等)。
两种类型的语言,差异如下:许多中、大型程序都是用编译型语言(例如 C/C++、Java、Fortran)完成,它们的源代码文件(source code)经过编译之后转为目标代码文件(object code),机器才能读取并执行目标代码文件;编译型语言高效,但是由于贴近于机器底层,难以执行上层的一些简单操作(例如 C++ 难以对某目录下的所有文件批量重命名),而解释型语言执行层面高于编译型语言,因此能轻松完成一些高级操作;脚本语言(Shell、Perl、Python、awk、Ruby 等)都是解释性语言。
(Python 是一种解释型语言,但是它采用了 Java 语言的 VM 机制,提供了编译功能,它的源代码文件经过编译后,产生了字节码文件(bytecode),可以节省加载模块的时间从而提高效率)
两种类型的语言,差异如下:许多中、大型程序都是用编译型语言(例如 C/C++、Java、Fortran)完成,它们的源代码文件(source code)经过编译之后转为目标代码文件(object code),机器才能读取并执行目标代码文件;编译型语言高效,但是由于贴近于机器底层,难以执行上层的一些简单操作(例如 C++ 难以对某目录下的所有文件批量重命名),而解释型语言执行层面高于编译型语言,因此能轻松完成一些高级操作;脚本语言(Shell、Perl、Python、awk、Ruby 等)都是解释性语言。
(Python 是一种解释型语言,但是它采用了 Java 语言的 VM 机制,提供了编译功能,它的源代码文件经过编译后,产生了字节码文件(bytecode),可以节省加载模块的时间从而提高效率)
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31391681/viewspace-2151674/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31391681/viewspace-2151674/