高级shell编程技巧
1、深入讨论<<
当shell看到<<的时候,它就会知道下一个词是一个分界符。在该分界符以后的内容都被当作输入,直到shell又看到该分界符(位于单独的一行)。这个分界符可以是你所定义的任何字符串。
该命令的一般形式为:
command <<word
text
word
2、shell 工具
2.1 创建保存信息的文件
任何脚本都应该能够创建临时文件或日志文件。在运行脚本做备份时,最好是保存一个
日志文件。这些日志文件通常在文件系统中保留几周,过时将被删除。
在开发脚本的时候,可能总要创建一些临时的文件。在正常运行脚本的时候,也要使用
临时文件保存信息,以便作为另外一个进程的输入。
2.1.1 、使用date命令创建日志文件
在创建日志文件时,最好能够使它具有唯一性,可以按照日志文件创建的日期和时间来
识别这些文件。我们可以使用date命令做到这一点。这样就能够使日期和时间成为日志文件名中的一部分。
为了改变日期和时间的显示格式,可以使用如下的命令:
date option + %format
在文件名中含有日期的一个简单办法就是使用置换。把含有你所需要的日期格式的变量
附加在相应的日志文件名后面即可。
2.1.2 、创建唯一的临时文件
变量$$中保存有你所运行的当前进程的进程号。可以使用它在我们运行的脚本中创建一个唯一的临时文件,因为该脚本在运行时的进程号是唯一的。我们只要创建一个文件并在后面附加上$$即可。在脚本结束时,只需删除带有$$扩展的临时文件即可。Shell将会把$ $解析为当前的进程号,并删除相应的文件,而不会影响以其他进程号做后缀的文件。
2.2、信号
信号就是系统向脚本或命令发出的消息,告知它们某个事件的发生。这些事件通常是内
存错误,访问权限问题或某个用户试图停止你的进程。信号实际上是一些数字。下表列出了
最常用的信号及它们的含义。
1 SIGHUP 挂起或父进程被杀死
2 SIGINT 来自键盘的中断信号,通常是<CTRL-C>
3 SIGQUIT 从键盘退出
9 SIGKILL 无条件终止
11 SIGSEGV 段(内存)冲突
15 SIGTERM 软件终止(缺省杀进程信号)
发送信号可以使用如下的格式:
kill [-signal no:| signal name] process ID
使用kill命令时不带任何信号或名字意味着使用缺省的信号15。可以使用如下的命令列出所有的信号:
kill -l
有些信号可以被应用程序或脚本捕获,并依据该信号采取相应的行动。另外一些信号不
能被捕获。例如,如果一个命令收到了信号9,就无法再捕捉其他信号。
在编写shell脚本时,只需关心信号1、2、3和1 5。当脚本捕捉到一个信号后,它可能会采取下面三种操作之一:
1) 不采取任何行动,由系统来进行处理。
2) 捕获该信号,但忽略它。
3) 捕获该信号,并采取相应的行动。
大多数的脚本都使用第一种处理方法,如果想要采取另外两种处理方法,必须使用trap命令。
2.3、trap
trap可以使你在脚本中捕捉信号。该命令的一般形式为:
trap name signal(s)
其中,name是捕捉到信号以后所采取的一系列操作。实际生活中,name一般是一个专门用来处理所捕捉信号的函数。Name需要用双引号(“ ”)引起来。Signal就是待捕捉的信号。脚本在捕捉到一个信号以后,通常会采取某些行动。最常见的行动包括:
1) 清除临时文件。
2) 忽略该信号。
3) 询问用户是否终止该脚本的运行。
常见的t r a p命令用法:
trap "" 2 3 忽略信号2和信号3,用户不能终止该脚本
trap"commands" 2 3 如果捕捉到信号2或3,就执行相应的commands命令
trap 2 3 复位信号2和3,用户可以终止该脚本
也可以使用单引号(‘’)来代替双引号(“”);其结果是一样的。
2.4、eval
eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描。这些需要进行两次扫描的变量有时被称为复杂变量。
3、运行级别脚本
如果希望在系统启动时自动运行某些应用程序、服务或脚本,或者在系统重启动时能够
正确地关闭这些程序,那么需要创建运行级别脚本。
能够创建运行级别脚本就意味着能够更灵活地控制系统。如果需要在某一个特定的运行
级别启动或停止程序,就得创建运行级别脚本(它们通常被称为rc.script)。
任何用关键字start或stop调用的、能够启动或停止程序运行的脚本都可以看作是一个
rc.script。注意,应当由用户来保证他或她所提交的脚本是一个有效的脚本,能够正确地启动或停止某一服务。
运行级别配置目录的机制使得rc.script只在系统切换运行级别时有效。它不负责检查某一运行级别中所有的特定服务是否都已经被启动或停止。这是shell编程者的事。
3.1、怎么知道系统中是否含有运行级别目录
rc.scripts一般保存在/etc/rcN.d或/etc/rc.d/rcN.d目录下,其中,N是一个数字。通常是7个,因为rcN.d目录的序号是从0到6。如果我们使用cd命令进入这些rcN.d目录,会发现这些目录中的rc.scripts实际上是一些链接。
3.2、确定当前的运行级别
如果想知道当前的运行级别,可以用下面的命令:
who –r
run-level 4 Apr 22 13:26 4 0 3
在‘run level’后面的数字就是当前的运行级别。后面的时间是系统最近一次重启动的时间。如果是LINUX系统,那么
$ runlevel
2 3
第一列表示系统的前一个运行级别,第二列表示系统当前的运行级别,在这里是3。
3.3、快速熟悉inittab
init进程是linux系统所有进程的起点,init进程的进程号是1,linux在完成内核引导后,就开始运行init程序。位于/etc目录下的文本文件inittab为init的配置文件。
inittab文件的格式为:id:runlevel:action:process,可使用man inittab察看联机文档,以下是部分命令行的简单注释:
#表示当前缺省运行级别为5
id:5:initdefault:
#启动时自动执行初始化脚本/etc/rc.d/rc.sysinit
si::sysinit:/etc/rc.d/rc.sysinit
#启动对应运行级别的守护进程(当前为5)
l5:5:wait:/etc/rc.d/rc 5
#在2,3,4,5运行级别上打开6个终端程序
#respawn表示若进程退出则再次运行
1:2345:respawn:/sbin/mingetty tty1
...
6:2345:respawn:/sbin/mingetty tty6
#在运行级别5下运行xdm窗口管理器
x:5:respawn:/etc/X11/perfdm -nodaemon
initdefault是一个特殊的action值,用来标识缺省的运行级别,5表示使用XDM的图形登陆方式,另一个常用的运行级别为3,表示基于字符终端的完全多用户模式
rc.sysinit是一个shell脚本,负责系统的初始化工作,包括激活交换分区,检查磁盘,加载磁盘模块等。
/etc/rc.d/rc是一个shell脚本,当参数为5时,会去执行/etc/rc.d/rc5.d/目录下的所有启动脚本,启动脚本通常是K或S开头的联机文件,对于以以S开头的启动脚本,将以start参数来运行。而如果发现存在相应以S打头的链接也存在K打头的链接,而且已经处于运行态了(以/var/lock/subsys/下的文件作为标志),则将首先以stop为参数停止这些已经启动了的守护进程,然后再重新运行。这样做是为了保证是当 init改变运行级别时,所有相关的守护进程都将重启。可通过chkconfig --list命令察看当前系统所有守护进程的状况
基本上linux系统的启动顺序为:bios自检 -> grub(或lilo)引导程序 -> 载入linux内核 -> 执行init进程 -> 系统初始化 -> 启动守护进程 -> 启动终端程序 -> 显示X windows登陆窗口
3.4、运行级别
init进程在系统完全就绪之前所做的最后几项工作之一就是执行缺省运行级别所包含的所有脚本。该进程是通过/etc/rc.d/rc或/etc/rc.init来启动这些脚本的。它的作用是首先杀死该运行级别所包含的进程再启动这些进程。
但是它怎么知道该启动或停止哪些服务呢?rc或rc.init脚本将会使用for循环来依次查看相应运行级别目录中的文件,给每一个链接名以K开头的相应脚本赋予参数stop;给每一个链接名以S开头的相应脚本赋予参数start。在运行级别切换时,上述脚本也会完成同样的工作,只不过根据相应的运行级别来启动或停止对应的脚本。
rcN.d目录中的脚本只是一些链接—真正的脚本保存在其他的目录中。它们通常都放置
在/usr/sbin/init.d或/etc/init.d目录中。如果是L I N U X系统,那么放置的目录是/etc/rc.d/init.d
在这个目录中含有一些能够启动或停止某一服务的脚本。这些脚本的名字最好能够表示出它所实现的功能,形如rc.<功能>。
下面是这类文件的部分列表。
rc.localfs rc.halt rc.reboot
一般来说, rc.scripts都应当能够接受这样的参数:
rc.name stop:停止该服务。
rc.name start:启动该服务。
可选的参数包括restart和status。其他任何参数都应当给出相应的用法说明。注意,可以手工运行这些脚本。
现在我们已经知道运行级别脚本应当具有什么样的功能,下一步就是把它们放置在相应
的rcN.d目录中。不过在此之前我们先来了解一下系统运行级别。
3.4.1 、各种运行级别
系统含有七种运行级别,不同的系统在某些运行级别上稍有差别。
在将一个脚本放置在不同的运行级别目录中之前,首先应当弄清楚打算在哪一个运行级
别启动或停止相应的服务?一旦弄清楚这一点,就可以接着进行下面的步骤了。
各个运行级别的用途:
运行级别0 启动和停止整个系统
运行级别1 单用户或管理模式
运行级别2 多用户模式;部分网络服务被启动。有些系统将其作为正常运行模式,而不是级别3
运行级别3 正常操作运行模式,启动所有的网络服务
运行级别4 用户定义的模式,可以使用该级别来定制所需要运行的服务
运行级别5 有些UNIX操作系统变体将其作为缺省X-windows模式,还有些系统把它作为系统维护模式
运行级别6 重启动
3.4.2 、运行级别脚本的格式
rcN.d目录中的脚本都是一些链接,这样是为了省去不必要的副本。这些链接的格式为:
Snnn.script_name
或
Knnn.script_name
其中,
S:代表启动相应的进程
K:代表杀死相应的进程
nn:是00至99的两位数字,不过在有些系统中是000至999三位数字。在不同目录中的链接应采用同一数字。script_name:相应脚本的文件名,根据所在操作系统的不同,它们可能位于下列目录中:
/usr/sbin/init.d
/etc/rc.d
/etc/init.d
当init进程调用相应的运行级别脚本时,杀进程按照从高到低的K序号进行,而启动进程按照从低到高的序号进行。如果使用的是LINUX系统,K序号将按照从高到低的顺序执行。
3.4.3 、安装运行级别脚本
如果想要安装自己的运行级别脚本,必须:
编写该脚本,确保它符合调用标准。
确信它能够启动或终止相应的服务。
将该脚本放置于(取决于操作系统)/etc/init.d或/usr/sbin/init.d或/etc/rc.d中。
在相应的rcN.d目录中按照合理的命名方式创建链接。
3.5、使用inittab来启动应用程序
我们还可以用其他的方法来启动应用程序。可以通过在inittab文件中加入相应的条目来做到这一点。比如系统检查的脚本需要在系统刚刚就绪之后运行。使用inittab是实现上述功能的理想途径。
3.6、启动和停止服务的其他方法
如果不想把/etc/inittab文件弄得过于杂乱,还有其他的方法可以实现启动和停止服务的功能。大多数系统都含有一个名为rc.local的文件,一般来说也是位于/etc目录下。该脚本文件将在inittab和运行级别脚本之后运行。可以在该文件中加入任何命令,或从中调用最习惯用的启动脚本。