第5章 嵌入式Linux的Shell编程_第1页
第5章 嵌入式Linux的Shell编程_第2页
第5章 嵌入式Linux的Shell编程_第3页
第5章 嵌入式Linux的Shell编程_第4页
第5章 嵌入式Linux的Shell编程_第5页
已阅读5页,还剩56页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章嵌入式Linux的Shell编程5.1shell简介5.2

shell基础编程5.3bash的内部命令5.4Shell程序的运行与调试方法5.5Shell编程实例5.1shell简介Shell是一种具备特殊功能的程序,它是介于使用者和UNIX/Linux操作系统之核心程序(kernel)间的一个接口。在UNIX/Linux系统中,常用的Shell有3种,分别是Bourneshell(AT&Tshell,在Linux下是bash)、Cshell(Berkeleyshell,在Linux下是tcsh)和Kornshell(Bourneshell的超集)。这3种shell在交谈(interactive)模式下的表现相当类似,但作为命令文件语言时,在语法和执行效率上就有些不同了。

Bourneshell是第一个有重要意义的标准的UNIXshell,V7(AT&T的第七版)UNIX是在1979年底被提出,且以它的创造者StephenBourne来命名。Bourneshell以Algol语言为基础来设计,主要被用来做自动化系统管理工作。虽然Bourneshell以简单和速度而受欢迎,但它缺少许多交谈性使用的特色,例如历程、别名和工作控制。大部份的系统管理命令文件,例如rcstart、stop与shutdown都是Bourneshell的命令档,且在单一使用者模式(singleusermode)下以root签入时它常被系统管理者使用。Bourneshell是由AT&T发展的,以简洁、快速著名。Bourneshell提示符号的默认值是$。

Cshell是在加州大学柏克来分校于70年代末期发展而成,而以2BSDUNIX的部分发行。这个shell主要是由BillJoy写成,提供了一些在标准Bourneshell所看不到的额外特色,在交谈式运用上作了一些改进,如命令列历程(history)、别名(alias)、内建算术、档名完成(filenamecompletion)、和工作控制(jobcontrol)。Cshell是以C程序语言作为基础,且它被用来当程序语言时,能共享类似的语法。因为Cshell是在大型机器上设计出来,且增加了一些额外功能,所以Cshell在小型机器上跑得较慢,即使在大型机器上跟Bourneshell比起来也显得缓慢。Cshell提示符号的默认值是%。

Kornshell是Bourneshell的超集(superset),由AT&T的DavidKorn所开发。它增加了一些特色,比Cshell更为先进。Kornshell的特色包括了可编辑的历程、别名、函式、正规表达式万用字符(regularexpressionwildcard)、内建算术、工作控制(jobcontrol)、共作处理(coprocessing)、和特殊的除错功能。Bourneshell几乎和Kornshell完全向上兼容(upwardcompatible),所以在Bourneshell下开发的程序仍能在Kornshell上执行。在Linux系统使用的Kornshell叫做pdksh,它是指PublicDomainKornShell。Kornshell提示符号的默认值也是$。在shell的语法方面,Kornshell是比较接近一般程序语言,而且它具有子程序的功能及提供较多的资料型态。至于Bourneshell,它所拥有的资料型态是这3种shell中最少的,仅提供字符串变量和布尔型态。在整体考量下Kornshell是三者中表现最佳者,其次为Cshell,最后才是Bourneshell,但是在实际使用中仍有其它应列入考虑的因素,如速度是最重要的选择时,很可能应该采用Bourneshell,因它是最基本的shell,执行的速度最快。

tcsh是近几年崛起的一个免费软件(Linux下的Cshell其实就是使用tcsh)执行,它虽然不是UNIX的标准配备,但是从许多地方都可以下载到它。如果开发者是Cshell的拥护者,可不妨试试tcsh。

Linux下的bash就是Bourneshell,是向下兼容的,Bourneshell融入许多Cshell与Kornshell的功能。如:(1)工作控制(jobcontorl)。bash支持了关于工作的讯号与指令。

(2)别名功能(aliases)。alias命令是用来为一个命令建立另一个名称,它的运作就像一个宏,展开成为它所代表的命令。别名并不会替代掉命令的名称,它只是赋予那个命令另一个名字。

(3)命令历程(commandhistory)Unix的Shell有很多种类,Linux系统继承了Unix系统中Shell的全部功能,现在默认使用的是bash。Shell具有如下突出特点。(1)把已有命令进行适当组合构成新的命令。(2)提供了文件名扩展字符(通配符,如*、?、[]),使得用单一的字符串可以匹配多个文件名,省去键入一长串文件名的麻烦。(3)可以直接使用Shell的内置命令,而不需创建新的进程,如Shell中提供的cd、echo、exit、pwd、kill等命令。为防止因某些Shell不支持这类命令而出现麻烦,许多命令都提供了对应的二进制代码,从而也可以在新进程中运行。(4)Shell允许灵活地使用数据流,提供通配符、输入/输出重定向、管道线等机制,方便了模式匹配、I/O处理和数据传输。(5)结构化的程序模块,提供了顺序流程控制、条件控制、循环控制等。(6)Shell提供了在后台执行命令的能力。(7)Shell提供了可配置的环境,允许创建和修改命令、命令提示符和其它的系统行为。(8)Shell提供了一个高级的命令语言,能够创建从简单到复杂的程序。这些Shell程序称为Shell脚本,利用Shell脚本,可把用户编写的可执行程序与Unix命令结合在一起,当作新的命令使用,从而便于用户开发新的命令。5.2

shell基础编程5.2.1环境变量与shell变量Shell不仅作为命令语言互动式地解释和执行用户输入的命令,还可以用来进行程序设计,它提供了定义变量和参数的手段以及丰富的程序控制结构。使用Shell编程类似于DOS中的批处理文件,称为Shellscript,又叫Shell程序或Shell命令文件。Shell的编程像高级程序设计语言一样,Shell也提供说明和使用变量的功能。对Shell来讲,所有变量的取值都是一个字串,Shell程序采用$var的形式来引用名为var的变量的值。Shell有以下几种基本类型的变量。(1)Shell定义的环境变量 export变量名也可以在给变量赋值的同时使用export命令:export变量名=变量值使用export说明的变量,在Shell以后运行的所有命令或程序中都可以访问到。常用的Shell环境变量有:①HOME:用于保存注册目录的完全路径名。②PATH:用于保存用冒号分隔的目录路径名,Shell将按PATH变量中给出的顺序搜索这些目录,找到的第一个与命令名称一致的可执行文件将被执行。③TERM:终端的类型。④UID:当前用户的识别字,取值是由数位构成的字串。⑤PWD:当前工作目录的绝对路径名,该变量的取值随cd命令的使用而变化。⑥PS1:主提示符,在特权用户下,默认的主提示符是#,在普通用户下,默认的主提示符是$。⑦PS2:在Shell接收用户输入命令的过程中,如果用户在输入行的末尾输入“\”然后回车,或者当用户按回车键时Shell判断出用户输入的命令没有结束时,就显示这个辅助提示符,提示用户继续输入命令的其余部分,默认的辅助提示符是>。(2)用户定义的变量Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则:

①首个字符必须为字母(a-z,A-Z)。

②中间不能有空格,可以使用下划线(_)。

③不能使用标点符号。

④不能使用bash里的关键字(可用help命令查看保留关键字)。用户可以按照下面的语法规则定义自己的变量:变量名=变量值注意,在定义变量时,变量名前不应加符号$,在引用变量的内容时则应在变量名前加$;在给变量赋值时,等号两边一定不能留空格。例如:$dir=/usr/meng/ff$echo$dir/usr/meng/ff←—显示结果$echodirdir←—显示结果在编写Shell程序时,为了使变量名和命令名相区别,建议所有的变量名都用大写字母来表示。若想在说明一个变量并对它设置为一个特定值后就不在改变它的值时,可以用下面的命令来保证一个变量的只读性:readonly变量名如果在赋给变量的值中要含有空格、制表符或换行符,那么,就应该用双引号把这个字符串括起来。例如,names="ZhangsanLisiWangwu"需要注意shell的默认赋值是字符串赋值。比如:var=1var=$var+1echo$var打印出来的不是2而是1+1。为了达到想要的效果有以下几种表达方式:let"var+=1"var=$[$var+1]var=`expr$var+1`#注意加号两边的空格,否则还是按照字符串的方式赋值。注意:前两种方式在bash下有效,在sh下会出错。let表示数学运算,expr用于整数值运算,每一项用空格隔开,$[]将中括号内的表达式作为数学运算先计算结果再输出。可以将一个命令的执行结果赋值给变量。有两种形式的命令替换:一种是使用倒引号引用命令,其一般形式是:`命令表`。

例如:将当前工作目录的全路径名存放到变量dir中,输入以下命令行:$dir=`pwd`另一种形式是:$(命令表)。上面的命令行也可以改写为:$dir=$(pwd)(3)位置参数执行Unix/Linux命令或Shell脚本时可以带有实参。在Shell脚本中的变量,在执行Shell程序时,用实参去替代这些变量。在Shell脚本中这类变量的名称很特别,分别是0、1、2……这类变量称作位置变量,也就是位置参数。位置参数是一种在调用Shell程序的命令行中按照各自的位置决定的变量,是在程序名之后输入的参数。位置参数之间用空格分隔,Shell取第一个位置参数替换程序文件中的$1,第二个替换$2,依次类推。$0是一个特殊的变量,它的内容是当前这个Shell程序的文件名,所以,$0不是一个位置参数,在显示当前所有的位置参数时是不包括$0的。因为它们与命令行上具体位置的实参相对应,命令名(脚本名)对应位置变量(位置参数)0。如果位置参数(位置变量)是由两个或更多个数字构成,那么,必须把它们用一对花括号括起来,如{10}、{11}。例如:$set`pwd;ls;date`$echo$1$2$3$9${10}${11}/home/mengqcbash_1ex112321:52:32如果在脚本中使用的位置参数不超过9个,那么只用$1~$9即可。但是,实际给定的命令行参数有可能多于9个,此时就需要用shift命令移动位置参数。每执行一次shift命令,就把命令行上的实参向左移一位,即相当于位置参数向右移动一个位置,如下所示。

上述虚线示出实参与位置参数的对应关系。可以看出,shift命令执行后新$1的值是原$2的值,新$2的值是原$3的值,依此类推。

shift命令不能将$0移走,所以经shift右移位置参数后,$0的值不会发生变化。(4)预定义变量预定义变量和环境变量相类似,也是在Shell一开始时就定义了的变量,是Shell预先定义了几个有特殊含义的Shell变量,它们的值只能由Shell根据实际情况进行赋值,而不能通过用户重新设置。所有预定义变量都是由$符和另一个符号组成的,常用的Shell预定义变量有:①$#命令行上实际参数的个数,但不包含Shell脚本名。②$*表示在命令行中实际给出的所有实参字符串,它并不仅限于9个实参。③$?上一条命令执行后的返回值(也称作“退出码”)。它是一个十进制数。多数Shell命令执行成功时,则返回值为0;如果执行失败,则返回非0值。④$$当前进程的进程号。⑤$!上一个后台命令对应的进程号,这是一个由1~5位数字构成的数字串。⑥$0当前执行的进程名。⑦$-由当前Shell设置的执行标志名组成的字符串。例如:set-xv这个命令行给Shell设置了标志-x和-v(用于跟踪输出)。(5)参数置换的变量Shell提供了参数置换功能以便用户可以根据不同的条件来给变量赋不同的值。参数置换的变量有4种,这些变量通常与某一个位置参数相联系,根据指定的位置参数是否已经设置类决定变量的取值,它们的语法和功能分别如下。①变量=${参数-word}:如果设置了参数,则用参数的值置换变量的值,否则用word置换。即这种变量的值等于某一个参数的值,如果该参数没有设置,则变量就等于word的值。②变量=${参数=word}:如果设置了参数,则用参数的值置换变量的值,否则把变量设置成word,然后再用word替换参数的值。注意,位置参数不能用于这种方式,因为在Shell程序中不能为位置参数赋值。③变量=${参数?word}:如果设置了参数,则用参数的值置换变量的值,否则就显示word并从Shell中退出,如果省略了word,则显示标准信息。这种变量要求一定等于某一个参数的值。如果该参数没有设置,就显示一个信息,然后退出,因此这种方式常用于出错指示。④变量=${参数+word}:如果设置了参数,则用word置换变量,否则不进行置换。所有这4种形式中的“参数”既可以是位置参数,也可以是另一个变量,只是用位置参数的情况比较多。5.2.2

Shell特殊字符Shell中除使用普通字符外,还使用了一些特殊字符,它们有特定的含义,如通配符“*”和“?”、管道线(|)及单引号、双引号等。在使用时应注意它们表示的意义和作用范围。1.一般通配符通配符用于模式匹配,如文件名匹配、路径名搜索、字符串查找等。常用的通配符有四种:(1)*匹配任意字符0次或多次出现。例如,f*可以匹配以f打头的任意字符串。但应注意,文件名前面的圆点(.)和路径名中的斜线(/)必须显式匹配。(2)?匹配任意一个字符,例如,f?匹配f1、fa、fb等,但不能匹配f、fabc、f12等。(3)[]其中有一个字符组,它匹配该字符组所限定的任何一个字符。该字符组可以由直接给出的字符组成,也可以由表示限定范围的起始字符、终止字符及中间一个连字符(-)组成。例如,f[a-d]与f[abcd]作用相同。(4)!表示不在一对方括号中所列出的字符。例如,f[!1—9].c表示以f打头,后面一个字符不是数字1至9的.c文件名,它匹配fa.c、fb.c、fm.c等。在一个正则表达式中,可以同时使用“*”和“?”。2.模式表达式模式表达式是那些包含一个或多个通配符的字。bash除支持一般通配符外,还提供了特有的扩展模式匹配表达式,其形式和含义如下:(1)*(模式表):匹配给定模式表中“模式”的0次或多次出现,各模式之间以“|”分开。例如,file*(.c|.o)将匹配文件file、file.c、file.o、file.c.c、file.0.0、file.c.o、file.o.c等,但不匹配file.h或file.s等。(2)+(模式表)匹配给定模式表中“模式”的1次或多次出现,各模式之间以“|”分开。例如,file+(.c|.o)匹配文件file.c、file.o、file.c.o、file.c.c等,但不匹配file。(3)?(模式表):匹配模式表中任何一种“模式”的0次或1次出现,各模式之间以“|”分开。例如,file?(.c|.o)只匹配file、file.c和file.0,它不匹配多个模式或模式的重复出现,即不匹配file.c.c、file.c.0等。(4)@(模式表):仅匹配模式表中给定“模式”的一次出现,各模式之间以“|”分开。例如,file@(.c|.0)匹配file.c和file.0,但不匹配file、file.c.c、file.c.o等。(5)!(模式表):除给定模式表中的一个“模式”之外,它可以匹配其它任何东西。可以看出,模式表达式的定义是递归的,每个表达式中都可以包含一个或多个模式。例如file*(.[cho]|.sh)是合法的模式表达式。但在使用时应注意,由于带“*”和“+”的表达式可以匹配给定模式的组合,若利用此种表达式去删除文件就存在危险,有可能误将系统配置文件删除。因此,必须小心使用。3.引号在Shell中引号分为三种:单引号、双引号和倒引号。(1)双引号由双引号括起来的字符,除$、倒引号(`)和反斜线(\)仍保留其特殊功能外,其余字符均作为普通字符对待。“$”表示变量替换,即用其后指定的变量的值来代替$和变量;倒引号表示命令替换;仅当“\”后面的字符是下述字符之一时,“\”才是转义字符,这些字符是:“$”、“`”、“"”、“\”或换行符。转义字符告诉Shell不要对其后面的那个字符进行特殊处理,只是当作普通字符。例如:$echo"Mycurrentdiris`pwd`andlognameis$LOGNAME"Mycurrentdiris/home/mengqcandlognameismengqc(2)单引号由单引号括起来的字符都作为普通字符出现。例如,$echo'Thetimeis`date`,thefileis$HOME/abc'Thetimeis`date`,thefileis$HOME/abc(3)倒引号

倒引号括起来的字符串被shell解释为命令行,在执行时,Shell会先执行该命令行,并以它的标准输出结果取代整个倒引号部分。在前面示例中已经见过。例如,$echocurrentdirectoryis`pwd`currentdirectoryis/home/mengqc4.注释

Shell程序中以“#”开头的正文行表示注释。例如:#!/bin/bash#Ifnoarguments,thenlistingthecurrentdirectory.#Otherwise,listingeachsubdirectory.iftest$#=0thenls·elseforidols-l$i|grep'^d'donefi5.2.3

Shell程序设计的流程控制1.测试命令test命令用于检查某个条件是否成立,它可以进行数值、字符和文件3个方面的测试,其测试符和相应的功能分别如下。(1)数值测试①-eq等于则为真。②-ne不等于则为真。③-gt大于则为真。④-ge大于等于则为真。⑤-lt小于则为真。⑥-le小于等于则为真。(2)字串测试①=等于则为真。②!=不相等则为真。③-z字串字串长度伪则为真。④-n字串字串长度不伪则为真。(3)文件测试:①-e文件名如果文件存在则为真。②-r文件名如果文件存在且可读则为真。③-w文件名如果文件存在且可写则为真。④-x文件名如果文件存在且可执行则为真。⑤-s文件名如果文件存在且至少有一个字符则为真。⑥-d文件名如果文件存在且为目录则为真。⑦-f文件名如果文件存在且为普通文件则为真。⑧-c文件名如果文件存在且为字符型特殊文件则为真。⑨-b文件名如果文件存在且为块特殊文件则为真。另外,Linux还提供了与(!)、或(-o)、非(-a)3个逻辑操作符,用于将测试条件连接起来,其优先顺序为:!最高,-a次之,-o最低。同时,bash也能完成简单的算术运算,格式如下:$[expression]例如:var1=2var2=$[var1*10+1]则var2的值为21。2.if条件语句Shell程序中的条件分支是通过if条件语句来实现的,其一般格式为:if条件命令串then条件为真时的命令串else条件为假时的命令串fi大多数情况下,可以使用测试命令来对条件进行测试,比如可以比较字符串、判断文件是否存在及是否可读等等……通常用"[]"来表示条件测试,注意这里的空格很重要,要确保方括号前后的空格。;[-f"somefile"]:判断是否是一个文件;[-x"/bin/ls"]:判断/bin/ls是否存在并有可执行权限;[-n"$var"]:判断$var变量是否有值;["$a"="$b"]:判断$a和$b是否相等执行mantest可以查看所有测试表达式可以比较和判断的类型。例如:#!/bin/shif[${SHELL}="/bin/bash"];thenecho"yourloginshellisthebash(bourneagainshell)"elseecho"yourloginshellisnotbashbut${SHELL}"fi变量$SHELL包含有登录shell的名称,用它和/bin/bash进行比较以判断当前使用的shell是否为bash。在if条件语句中,也经常使用&&和||操作符,例如:[-f"/etc/shadow"]&&echo"Thiscomputerusesshadowpasswords"这里的&&就是一个快捷操作符,如果左边的表达式为真则执行右边的语句,也可以把它看作逻辑运算里的与操作。上述脚本表示如果/etc/shadow文件存在,则打印”Thiscomputerusesshadowpasswords”。同样shell编程中还可以用或操作(||),例如:#!/bin/shmailfolder=/var/spool/mail/james[-r"$mailfolder"]||{echo"Cannotread$mailfolder";exit1;}echo"$mailfolderhasmailfrom:"grep"^From"$mailfolder3.case语句if条件语句用于在两个选项中选定一项,而case条件选择为用户提供了根据字串或变量的值从多个选项中选择一项的方法,其格式如下:casestringin

exp-1)若干个命令行1;;

exp-2)若干个命令行2;;

……

*)其他命令行esacShell通过计算字串string的值,将其结果依次和运算式exp-1,exp-2等进行比较,直到找到一个匹配的运算式为止。如果找到了匹配项,则执行它下面的命令直到遇到一对分号(;;)为止。在case运算式中也可以使用Shell的通配符(“*”、“?”、“[]”)。通常用*作为case命令的最后运算式以便在前面找不到任何相应的匹配项时执行“其他命令行”的命令。

file命令可以辨别出一个给定文件的文件类型,如:filelf.gz,其输出结果为:lf.gz:gzipcompresseddata,deflated,originalfilename,lastmodified:MonAug2723:09:182001,os:Unix利用这点写了一个名为smartzip的脚本,该脚本可以自动解压bzip2,gzip和zip类型的压缩文件:#!/bin/shftype=`file"$1"`#Note'and`isdifferentcase"$ftype"in"$1:Ziparchive"*)unzip"$1";;"$1:gzipcompressed"*)gunzip"$1";;"$1:bzip2compressed"*)bunzip2"$1";;*)echo"File$1cannotbeuncompressedwithsmartzip";;esac上面的脚本程序使用了一个特殊变量$1,该变量包含有传递给该脚本的第一个参数值。也就是说,当运行:smartziparticles.zip$1就是字符串articles.zip。4.select语句select表达式是bash的一种扩展应用,常用于交互式场合。用户可以从一组不同的值中进行选择:

selectvarin... ;do

break;done....now$varcanbeused....

下面是一个简单的示例:

#!/bin/shecho"WhatisyourfavouriteOS?"selectvarin"Linux""GnuHurd""FreeBSD""Other";dobreak;doneecho"Youhaveselected$var"如果以上脚本运行出现select:NOTFOUND将#!/bin/sh改为#!/bin/bash该脚本的运行结果如下:

WhatisyourfavouriteOS?1)Linux2)GnuHurd3)FreeBSD4)Other#?1YouhaveselectedLinux5.for循环for循环对一个变量的可能的值都执行一个命令序列。赋给变量的几个数值既可以在程序内以数值列表的形式提供,也可以在程序以外以位置参数的形式提供。for循环的一般格式为:for变量名[in数值列表]do若干个命令行done变量名可以是用户选择的任何字串,如果变量名是var,则在in之后给出的数值将顺序替换循环命令列表中的$var。如果省略了in,则变量var的取值将是位置参数。对变量的每一个可能的赋值都将执行do和done之间的命令列表。例如:下面是一个实用的脚本showrpm,其功能是打印一些RPM包的统计信息。#!/bin/sh#listacontentsummaryofanumberofRPMpackages#USAGE:showrpmrpmfile1rpmfile2...#EXAMPLE:showrpm/cdrom/RedHat/RPMS/*.rpmforrpmpackagein$*;doif[-r"$rpmpackage"];thenecho"===============$rpmpackage=============="rpm-qi-p$rpmpackageelseecho"ERROR:cannotreadfile$rpmpackage"fiDone上面脚本程序中出现了第二个特殊变量$*,该变量包含有输入的所有命令行参数值。如果运行showrpmopenssh.rpmw3m.rpmwebgrep.rpm,那么$*就包含有3个字符串,即openssh.rpm,w3m.rpm和webgrep.rpm。6.while和until循环while和until命令都是用命令的返回状态值来控制循环的。While循环的一般格式为:while若干个命令行1do若干个命令行2done只要while的“若干个命令行1”中最后一个命令的返回状态为真,while循环就继续执行do...done之间的“若干个命令行2”。until命令是另一种循环结构,它和while命令相似,其格式如下:

until若干个命令行1

do若干个命令行2doneuntil循环和while循环的区别在于:while循环在条件为真时继续执行循环,而until则是在条件为假时继续执行循环。7.无条件控制语句break和continuebreak用于立即终止当前循环的执行,而contiune用于不执行循环中后面的语句而立即开始下一个循环的执行。这两个语句只有放在do和done之间才有效。8.函数定义在Shell中还可以定义函数。函数实际上也是由若干条Shell命令组成的,因此它与Shell程序形式上是相似的,不同的是它不是一个单独的进程,而是Shell程序的一部分。函数定义的基本格式为:functionname{若干命令行}调用函数的格式为:functionnameparam1param2…9.命令分组在Shell中有两种命令分组的方法:()和{}。前者当Shell执行()中的命令时将再创建一个新的子进程,然后这个子进程去执行圆括弧中的命令。当用户在执行某个命令时不想让命令运行时对状态集合(如位置参数、环境变量、当前工作目录等)的改变影响到下面语句的执行时,就应该把这些命令放在圆括弧中,这样就能保证所有的改变只对子进程产生影响,而父进程不受任何干扰。{}用于将顺序执行的命令的输出结果用于另一个命令的输入(管道方式)。当我们要真正使用圆括弧和花括弧时(如计算运算式的优先顺序),则需要在其前面加上转义符(\)以便让Shell知道它们不是用于命令执行的控制所用。10.信号trap命令用于在Shell程序中捕捉信号,之后可以有3种反应方式:(1)执行一段程序来处理这一信号。(2)接受信号的默认操作。(3)忽视这一信号。trap对上面3种方式提供了3种基本形式:第一种形式的trap命令在Shell接收到与signallist清单中数值相同的信号时,将执行双引号中的命令串。trap'commands'signal-listtrap"commands"signal-list为了恢复信号的默认操作,使用第二种形式的trap命令:trapsignal-list第三种形式的trap命令允许忽略信号:trap""signal-list注意:(1)对信号11(段违例)不能捕捉,因为Shell本身需要捕捉该信号去进行内存的转储。(2)在trap中可以定义对信号0的处理(实际上没有这个信号),Shell程序在其终止(如执行exit语句)时发出该信号。(3)在捕捉到signal-list中指定的信号并执行完相应的命令之后,如果这些命令没有将Shell程序终止的话,Shell程序将继续执行收到信号时所执行的命令后面的命令,这样将很容易导致Shell程序无法终止。另外,在trap语句中,单引号和双引号是不同的。当Shell程序第一次碰到trap语句时,将把commands中的命令扫描一遍。此时若commands是用单引号括起来的话,那么Shell不会对commands中的变量和命令进行替换,否则commands中的变量和命令将用当时具体的值来替换。5.3bash的内部命令bash命令解释套装程序包含了一些内部命令。内部命令在目录列表时是看不见的,它们由Shell本身提供。常用的内部命令有:echo,eval,exec,export,readonly,read,shift,wait和点(.)。下面简单介绍其命令格式和功能。1.echo命令格式:echoarg功能:在屏幕上显示出由arg指定的字串。2.eval命令格式:evalargs功能:当Shell程序执行到eval语句时,Shell读入参数args,并将它们组合成一个新的命令,然后执行。3.exec命令格式:exec命令参数功能:当Shell执行到exec语句时,不会去创建新的子进程,而是转去执行指定的命令,当指定的命令执行完时,该进程(也就是最初的Shell)就终止了,所以Shell程序中exec后面的语句将不再被执行。4.export命令格式:export变量名或:export变量名=变量值功能:Shell可以用export把它的变量向下带入子Shell,从而让子进程继承父进程中的环境变量。但子Shell不能用export把它的变量向上带入父Shell。注意:不带任何变量名的export语句将显示出当前所有的export变量。5.readonly命令格式:readonly变量名功能:将一个用户定义的Shell变量标识为不可变。不带任何参数的readonly命令将显示出所有只读的Shell变量。6.read命令格式:read变量名表功能:从标准输入设备读入一行,分解成若干字,赋值给Shell程序内部定义的变量。7.shift语句功能:shift语句按如下方式重新命名所有的位置参数变量,即$2成为$1,$3成为$2…在程序中每使用一次shift语句,都使所有的位置参数依次向左移动一个位置,并使位置参数$#减1,直到减到0为止。8.wait功能:使Shell等待在后台启动的所有子进程结束。wait的返回值总是真。9.exit功能:退出Shell程序。在exit之后可有选择地指定一个数位作为返回状态。10.“.”(点)命令格式:.Shell程序文件名功能:使Shell读入指定的Shell程序文件并依次执行文件中的所有语句。5.4Shell程序的运行与调试方法1.Shell程序的运行方法执行Shell程序的方法有3种。(1)输入定向到Shell脚本这种方式是用输入重定向方式让Shell从给定文件中读入命令行并进行相应处理。其一般形式是:$bash<脚本名这实际上是调用一个新的bash命令解释程序,而把Shell程序文件名作为参数传递给它。新启动的Shell将去读指定的文件,可执行文件中列出的命令,当所有的命令都执行完后结束。该方法的优点是可以利用Shell调试功能。例如:$bash<ex1Shell从文件ex1中读取命令行,并执行它们。当Shell到达文件末尾时就终止执行,并把控制返回到Shell命令状态。此时,脚本名后面不能带参数。(2)以脚本名作为参数

其一般形式是:$bash脚本名

[参数]例如:$bashex2/usr/meng/usr/zhang其执行过程与上一种方式一样,但这种方式的好处是能在脚本名后面带有参数,从而将参数值传递给程序中的命令,使一个Shell脚本可以处理多种情况,就如同函数调用时可根据具体问题给定相应的实参。

如果以目前Shell(以·表示)执行一个Shell脚本,则可以使用如下简便形式:$·脚本名[参数]以Shell脚本作为Shell的命令行参数,这种方式可用来进行程序调试。

(3)将Shell脚本的权限设置为可执行,然后在提示符下直接执行它。

通常用户是不能直接执行由正文编辑器(如vi)建立的Shell脚本的,因为直接编辑生成的脚本文件没有“执行”权限。如果要把Shell脚本直接当作命令执行,就需要利用命令chmod将它置为有“执行”权限。例如,$chmoda+xex2就把Shell脚本ex2置为对所有用户都有“执行”权限。然后,在提示符后输入脚本名ex2就可直接执行该文件。注意,此时该脚本所在的目录应被包含在命令搜索路径(PATH)中。例如:$ex2Shell接收用户输入的命令(脚本名),并进行分析。如果文件被标记为可执行的,但不是被编译过的程序,Shell就认为它是一个Shell脚本。Shell将读取其中的内容,并加以解释执行。所以,从用户的观点看,执行Shell脚本的方式与执行一般的可执行文件的方式相似。2.bash程序的调试在编程过程中难免会出错,有的时候,调试程序比编写程序花费的时间还要多,Shell程序同样如此。Shell程序的调试主要是利用bash命令解释程序的选择项。调用bash的形式是:bash-选择项Shell程序文件名几个常用的选择项是:●–e:如果一个命令失败就立即退出。●–n:读入命令但是不执行它们。●-u:置换时把未设置的变量看做出错。●-v:当读入Shell输入行时把它们显示出来。●-x:执行命令时把命令和它们的参数显示出来。上面的所有选项也可以在Shell程序内部用“set-选择项”的形式引用,而“set+选择项”则将禁止该选择项起作用。如果只想对程序的某一部分使用某些选择项时,则可以将该部分用上面两个语句包围起来。(1)未置变量退出和立即退出未置变量退出特性允许用户对所有变量进行检查,如果引用了一个未赋值的变量就终止Shell程序的执行。Shell通常允许未置变量的使用,在这种情况下,变量的值为空。如果设置了未置变量退出选择项,则一旦使用了未置变量就显示错误信息,并终止程序的运行。未置变量退出选择项为-u。当Shell运行时,若遇到不存在或不可执行的命令、重定向失败或命令非正常结束等情况时,如果未经重新定向,该出错信息会显示在终端屏幕上,而Shell程序仍将继续执行。要想在错误发生时迫使Shell程序立即结束,可以使用-e选项将Shell程序的执行立即终止。(2)Shell程序的跟踪调试Shell程序的主要方法是利用Shell命令解释程序的-v或-x选项来跟踪程序的执行。-v选择项使Shell在执行程序的过程中,把它读入的每一个命令行都显示出来,而-x选择项使Shell在执行程序的过程中把它执行的每一个命令在行首用一个+加上命令名显示出来。并把每一个变量和该变量所取的值也显示出来。因此,它们的主要区别在于:在执行命令行之前无-v,则显示出命令行的原始内容,而有-v时则显示出经过替换后的命令行的内容。除了使用Shell的-v和-x选择项以外,还可以在Shell程序内部采取一些辅助调试的措施。例如,可以在Shell程序的一些关键地方使用echo命令把必要的信息显示出来,它的作用相当于C语言中的printf语句,这样就可以知道程序运行到什么地方及程序目前的状态。5.5Shell编程实例Shell程序可以存放在文件中,这种被Shell解释执行的命令文件称为Shell脚本(ShellScript)。Shell脚本可包含任意从键盘键入的Linux命令。建立Shell脚本的步骤同建立普通文本文件的方式相同,利用编辑器(如vi)进行程序录入和编辑并保存。任何优秀的脚本都应该具有帮助和输入参数。有经验的脚本编程人员都是先编写了一个比较完整的框架脚本(framework.sh),该脚本包含了大多数脚本需要的框架结构。当开发人员需要编写新的脚本时,只需把框架脚本复制到另一个待写的新的脚本文件中,然后再插入自己的函数。如执行cpframework.shmyscript命令,再插入自己的函数。下面列举几个实例来说明Shell的编程。例5.1编写一个二进制到十进制的转换的Shell程序(b2d.sh)。脚本b2d.sh将二进制数(比如1101)转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子。#!/bin/sh#vim:setsw=4ts=4et:help(){cat<<HELPb2d--convertbinarytodecimalUSAGE:b2d[-h]binarynumOPTIONS:-hhelptextEXAMPLE:b2d111010willreturn58HELPexit0}error(){#printanerrorandexitecho"$1"exit1}

lastchar(){#returnthelastcharacterofastringin$rvalif[-z"$1"];then#emptystringrval=""returnfi#wcputssomespacebehindtheoutputthisiswhyweneedsed:numofchar=`echo-n"$1"|wc-c|sed's///g'`#nowcutoutthelastcharrval=`echo-n"$1"|cut-b$numofchar`}

chop(){#removethelastcharacterinstringandreturnitin$rvalif[-z"$1"];then#emptystringrval=""returnfi#wcputssomespacebehindtheoutputthisiswhyweneedsed:numofchar=`echo-n"$1"|wc-c|sed's///g'`if["$numofchar"="1"];then#onlyonecharinstringrval=""returnfinumofcharminus1=`expr$numofchar"-"1`#nowcutallbutthelastchar:rval=`echo-n"$1"|cut-b-$numofcharminus1`#原来的rval=`echo-n"$1"|cut-b0-${n

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论