第二章 shell程序设计
本章介绍以下内容:
什么是shell
基本思路
微妙的语法:变量,条件判断和程序控制
命令列表
函数
命令和命令的执行
here文档
调试
grep命令和正则表达式
find命令
shell执行shell程序,这些程序通常称为脚本,它们是在运行时解释执行的。这使得调试工作比较容易进行,因为可以逐行地执行指令,而且节省了重新编译的时间。然而,这也使得shell不适合用来完成时间紧迫型和处理器忙碌型的任务。
UNIX架构非常依赖于代码的高度可重用性,如果你编写了一个小巧而简单的工具,其他人就可以将它作为一根链条上的某个环节来构成一条命令。
什么是shell
shell是一个作为用户与linux系统间接口的程序,它允许用户向操作系统输入需要执行的命令。这点与windows的命令提示符类似,但是Linxu shell的功能更强大。
shell(bash和csh)以及X视窗系统和其他程序环绕在linux内核的周围。在linux系统中,总是作为/bin/sh安装的标准shell是GNU工具集中的bash。在大多数linux发行版中,默认的shell程序/bin/sh实际上是对程序/bin/bash的一个连接。
可以使用/bin/bash --version查看bash的版本号
2.4管道和重定向
介绍如何对linxu程序的输入输出进行重定向
重定向输出:
$ ls -1 > lsoutput.txt
这条命令把ls命令的输出保存到文件lsoutput.txt中。
文件描述符0代表一个程序的标准输入,文件描述符1代表一个程序的标准输出,文件描述符2代表标准错误输出。
>操作符把标准输出重定向到一个文件。在默认情况下,如果该文件已经存在,它的内容将被覆盖。
用>>操作符将输出内容附加到一个文件中。例如:
$ ps >> lsoutput.txt
这条命令会将ps命令的输出附加到特定文件的尾部。
如果想对标准错误输出进行重定向,需要把重定向的文件描述符编号加载>操作符的前面。因为标准错误输出的文件描述符是2,所以使用2>操作符。当需要丢掉错误信息并阻止它显示在屏幕上时,这个方法很有用。
管道
可以用管道操作符|来连接进程,linux与MS-DOS不同,在linux下通过管道连接的进程可以同时运行,并且随着数据流在它们之间的传递可以自动地进行协调。例如,可以使用sort命令对ps命令的输出进行排序。
如果不使用管道,则必须分几个步骤来完成这个任务,如下所示:
$ ps > psout.txt
$ sort psout.txt > pssort.out
一个更精巧的解决方案是用管道来连接进程,如下所示:
$ ps | sort > pssort.out
作为程序设计语言的shell
编写shell脚本程序有两种方式,可以输入一系列命令让shell交互执行它们,也可以把这些命令保存到一个文件中,然后将这个文件作为程序来调用。
交互式程序
在命令行上直接输入shell脚本是一种测试短小代码段的简单而快捷的方式。
假如想要从大量C语言源文件中查找包含字符串POSIX的文件。与其使用grep命令在每个文件中搜索字符串,然后再分别列出包含该字符串的文件,不如用下面交互式脚本来执行整个操作:
$ for file in *
> do
> if grep -1 POSIX $file
> then
> more $file
> fi
> done
在这个例子中,grep命令输出它找到的包含POSIX字符串的文件,然后more命令将文件的内容显示在屏幕上,最后,返回shell提示符。shell还提供了通配符扩展,通配符×来匹配一个字符串,通配符?来匹配单个字符,而[set]允许匹配方括号中任何一个单个字符,[^set]对方括号中的内容取反,即匹配除给定字符集中字符以外的字符。扩展的花括号{}允许将任意的字符串组放在一个集合中。例如
$ ls my_{finger, toe}s
这个命令将列出文件my_fingers和my_toes,它使用shell来检查当前目录下的每个文件。
有经验的linux用户可能使用另一种更有效的方式来执行这个简单的操作。使用命令:
$ more ‘grep -l POSIX *‘
或者是命令:
$ more $(grep -l POSIX *)
此外,下面的命令将输出包含POSIX字符串的文件名:
$ grep -1 POSIX* | more
上面的脚本中,shell利用其他命令(如grep和more)来完成主要的工作。shell本身只是允许将几个现有的命令结合在一起,构成一个新的功能强大的命令。
如果每次想要执行一系列命令时,都要经过这么一个过程,非常麻烦。因此只需要将这些命令保存在一个文件中,即我们常说的shell脚本,这样就可以随时执行。
创建脚本
使用vim创建一个包含命令的文件,将其命名为first。
程序中的注释以#符号开始,一直持续到该行的结束。第一行#!/bin/sh,它是一种特殊的注释,#!字符告诉系统同一行上紧跟在它后面的那个参数是用来执行本文件的程序。/bin/sh是默认的shell程序。
exit命令的作用是确保脚本程序能够返回一个有意义的退出码。当程序以交互方式运行时,很少需要检查它的退出码,但是从另一个脚本程序里调用这个脚本程序并查看它是否执行成功,那么返回一个适当的退出码是必要的。
在shell程序设计里,0表示成功。
一般情况下,Linux和UNIX很少使用文件扩张名来决定文件的类型。大多数预安装的脚本程序并没有使用任何文件扩张名,检查这些文件是否是脚本程序的最好方法是使用file命令,例如file first或者file /bin/bash。
运行脚本文件有两种方法,比较简单的方法是调用shell,并把脚本文件名当成一个参数,如下所示:
$ /bin/sh first
这可以工作,但如果能像对待其他Linxu命令那样,只输入脚本程序的名字就可以调用它就更好了。你可以使用chmod命令来改变这个文件的模式,使得这个文件可以被所有用户执行,如下所示:
$ chmod +x first
然后可以用下面的命令来执行它:
$ first
你可能会看到一条错误信息来告诉你未找到命令。这种情况很可能发生,因为shell环境变量PATH并没有被设置为在当前目录下查找要执行的命令。一种方法是在命令行上直接输入命令PATH=$PATH:.,然后退出登陆后再重新登陆进来。另外,也可以在保存脚本程序的目录中输入命令./first,该命令的作用是把脚本程序的完整的相对路径告诉shell。
用./来指定路径还有另一个好处,它能够保证不会意外执行系统中与你的脚本文件同名的另一个命令。