shell学习笔记一--总括

Shell 脚本编程是 Unix/Linux 系统管理员应当具备的一项非常重要的技能,优秀管理员用 shell 脚本完成绝大多数工作,所以他们有足够的时间喝咖啡泡论坛。然而,要掌握这一技能并不十分容易,这需要了解相当数量的知识,并进行大量的练习和实践。笔者丝毫不敢说自己已经掌握了这一技能,我写这些文章只是为了把学习的历程记录下来,如果恰好也对你有所帮助我很荣幸。
首先,我们来解决必须回答的问题: shell 是什么?要回答这个问题必须先清楚 Unix/Linux 系统的结构。我们把这个结构简单分为两部分:系统内核――实用程序。系统内核是系统的心脏,从打开计算机自检时就驻留在计算机内存,直至计算机关闭;而实用程序驻留在计算机磁盘上,仅当需要时才调入内存。
那么 shell 是什么呢? shell 是一种实用程序,实际上所有 Unix/Linux 命令都是一个实用程序!每当系统允许用户登陆时,系统(准确地讲是 init 程序)为每个终端启动 getty getty 做一些事情然后在分配给他的终端上显示 ”login:” 等待用户输入信息。一旦用户键入信息并以回车结束, getty 程序就会消失,同时启动 login 程序完成登陆处理。用户成功登陆后,将会启动一个重量级的程序,那就是 shell
Shell 为什么那么重要呢?因为他有很多很强大的功能:
一、 执行程序: shell 负责解释并执行终端请求的程序。
二、 变量和文件名的替换: shell 会解释一些特殊的符号来进行替换。
三、 I/O 重定向:将输入和输出重定向到别的地方(不再是标准的键盘和屏幕)。
四、 管道线连接: shell 可以把多个命令连接在一起,就像管道一样。
五、 环境控制: shell 控制着用户的环境,你可以根据需要通过 shell 来改变环境。
六、 解释型程序设计语言:可以类似于 C (尽管没那么强大)那样编写复杂的程序。 下面我们的详细内容都是围绕上面六大功能展开的,在这之前先说明一下 shell 脚本又是什么?把 shell 能够解释的命令一条接一条写到文件里,加入上面提到的一些功能,并给该文件可以执行的权限,那么一个 shell 脚本就诞生了。换句话说,当你掌握了这些功能也就基本上掌握了编写 shell 脚本的技能了!
――程序执行
shell 负责解释并执行终端请求的程序,这里的程序大多数情况都是指 Unix/Linux 命令。 Shell 所涉及到的每条命令都遵循相同的基本格式:
程序名   参数表
    Shell 扫描命令行,并判断要执行的程序名字以及要传给程序什么参数(这里我们认为选项是参数的一部分)。
    Shell 用特定的字符去判断程序名的起止位置。这些字符被称为空白字符,有空格、 TAB 和换行符(回车), shell 会忽略掉多出的空白字符。键入命令: mv file temp shell 扫描命令行,并提取从该行开始到第一个空白字符为止的字符串作为将执行的程序名: mv ;接下去,到下一个空白字符之前的字符序列作为传给 mv 的第一个参数: file ;再接着到下一个空白字符(这里是换行符之前的字符序列是传给命令 mv 的第二个参数: temp 。分析完命令之后, shell 就会执行 mv 命令,同时传给它两个参数 file temp 。后面的任务就交给 mv 去完成了。注意, Unix/Linux 系统绝大多数情况是严格区分大小写的!
     前面提过,多个空白字符将被 shell 忽略。这就是说,当 shell 处理命令行:
echo     when    do    we  eat?
时,该命令行给 echo 程序 4 个参数: when do we eat
     因为 echo 得到参数后,只是将他们显示在终端上,并用一个空格字符分隔各个参数,因此下面的输出就很容易理解了:
 
  $echo     when    do    we  eat?
When do we eat?
$
事实上, echo 命令根本看不见那些空白字符:他们已被 shell “吞”掉了!
 
――变量和文件名的替换
与其他程序设计语言一样, shell 允许你给变量赋值。任何时候,在命令行中指定一个变量,并且在其前面冠以美元符号, shell 都会在这个位置用已赋给该变量的值来替换。我们后面还会详细讨论这个主题。
Shell 也在命令行执行文件名替换。实际上,在判定要执行的程序名及其参数之前,它先扫描命令行,寻找文件名替换字符 * ,?,或 […] 。假如当前目录包含如下文件:
$ls
file1
file2
file3
$
现在对 echo 命令做文件名替换:
$echo *
file1 file2 file3
$
有多少个参数传给了 echo 程序,一个还是 4 个?因为我们知道 shell 会执行文件名替换,所以答案是 4 个。当 shell 分析命令行:
echo *
时,它识别出特殊字符 * ,并在命令行中将 * 替换为当前工作目录下的所有文件:
echo file1 file2 file3
然后 shell 确定传给命令的参数。因此 echo 是看不见 * 的,当轮到它来处理时,看到的是命令行中键入 4 个参数。
 
―― I/O 重定向
在命令行中执行输入输出重定向也是 shell 的职责。它扫描命令行,看是否有特殊字符 < > >> 出现(还有字符 << ,将在后面讨论)。
键入命令:
echo Remember to order Law >reminder
时, shell 识别出特殊的重定向字符 > ,并提取命令行中的下一个词作为重定向输出结果的文件名,在上例中是 reminder 。如果 reminder 已经存在,而你也有对它的写入权限,原来的内容就丢失了(如果没有写入权限, shell 会提示一条错误信息)。
shell 开始程序的执行之前,它就将程序的标准输出重定向到指定文件。就程序而言,它根本不知道自己的输出被重定向了,它只是按照自己的方式将输出写入标准输出(通常是屏幕),并没有意识到 shell 已经将输出重定向到一个文件。
让我们来看两条几乎一样的命令:
$wc �Cl users
5 users
$wc �Cl < users
5
第一种情况下, shell 分析命令行,并判断要执行的程序名是 wc 以及要传给它的两个参数: -l users 。当 wc 开始执行时,它被传给了两个参数。第一个参数是 -l ,表示它将对行进行计数。第二个参数指明了要进行计数的文件名。所以, wc 打开文件 users ,统计行数,并在终端上打印出统计后的行数和相应文件名。
第二种情况下, wc 的操作稍微有一点不同。扫描命令行时, shell 识别出输入重定向字符 < ,紧跟着的那个词表示重定向数据院文件的名字。 Shell 从命令行“吞”掉 <users ,启动 wc 程序的执行,将他的标准输入重定向到文件 users ,并传递给它一个参数 -l 。这时 wc 开始执行,它发现只传给了自己一个参数 -l 。因为没有指定文件名, wc 将此作为统计标准输入上出现的行数的一种指示。因此, wc 在计数标准输入上的行数时,并未意识到,它实际上是在为文件 users 中的行进行计数。最终的结果显示在终端上――没有文件名,因为没有给过 wc 文件名。
 
――管道线连接
就像在命令行中搜索重定向字符一样, shell 也在搜索管道字符 | 。对每个它发现的管道字符,它将位于 | 前面的命令的标准输出连接到位于 | 后面的命令的标准输入。然后为这两个程序执行初始化(判断程序及其参数)。
因此在键入
$who | wc �Cl
时, shell 发现,管道字符隔开了命令 who wc 。它将前面命令的标准输出连接到后面命令的标准输入,然后为执行这两个程序做初始化。当执行 who 时,它产生一个登录人员的列表,并将结果写到标准输出:但它没有意识到,结果将不会送到终端,而是送到另一个命令。
wc 命令执行时,它识别出没有指定文件名,并在标准输入上统计行数。没有意识到标准输入不是来自于终端,而是来自于 who 命令的输出。
 
――环境控制
Shell 提供某些命令用于定制环境。环境包括用户的宿主目录、 shell 用于提醒用户键入命令的提示符号、每当请求运行某个程序而进行搜索的目录列表等等。详细的内容留到后续专门的章节继续讨论。
 
――解释型程序设计语言
Shell 有着自己的内部程序语言。它和 C 等其他高级程序设计语言最大的区别在于,这种语言是解释型的,他只是分析每条语句并执行,而不像其他语言那样需要经过编译才能执行。解释型的 shell 比编译型的程序更易于调试和修改,但他们的运行比等价的编译程序更耗时。
与大部分程序设计语言类似, shell 也具有 if case for while until 等判断、分支、循环结构,以及变量、数组和函数。这部分内容是脚本编程的重点和难点之一,后续也会有专门的章节来进行讨论。
 
好了, shell 总括就到这里了。总结一下,就是我们上面提到的六大功能。每一个功能都值得我们深入挖掘!事实上,你把这些功能挖掘得越透彻,你也就越容易写出更高质量的脚本。考虑不把篇幅写得过大,我将分几个主题来分别深入这些功能,有兴趣的朋友可以继续关注,链接地址也会后续提供。

你可能感兴趣的:(shell,职场,休闲)