1、shell编程与文本编辑vi剖析 shell编程与文本编辑8.1 shell编程8.1.1 shell基础shell是用C语言写的一个程序,它虽然与系统在一起并且作为系统的一部分提供给用户,但它不是操作系统的核心部分,它属于普通用户程序, 是命令的解释程序。8.1.1.1 shell命令及其表示方式 在shell程序中,一个命令行是由一系列的参量(argument)组成,参量与参数之间用空格或制表符隔开。第一个参量(位置计数为)即是命令的名字。 命令行的一般格式为:参数0 参数1 参数2 例如:cat file1 file2 file3在这个命令行中共有四个参量,第一个参数cat是命令的名字,
2、其余三个是文件名,其意思是打开文件file1、file2和file3。 如果命令行的第一个参量(即命令名的位置)是一个文件,而这个文件是可执行的,那么这个可执行的文件:A.可能是一个已经被编译过的程序,在这种情况下,直接运行这个程序即可 B.如果文件被标记为可执行的,但它不是被编译这的程序,那么就认为它是一 个shell过程。也就是说,它是一个包括了一些shell命令行的普通文本文件。遇到这种情况,shell读这个文件,并且执行包含在文件中的一些shell命令。8.1.1.2 shell程序所用的命令路径 通常,shell从文件系统的三个不同的地方查找所用的命令,查找的顺序为:当前目录、目录/
3、bin、目录/usr/bin。这样的机制,给多个用户执行的公共命令提供发一种方便的方法。8.1.1.3 文件名匹配符 shell程序使用了三种匹配符:(1)* 星号:匹配任何字符串,包括空字符,但不含符号“.” 例如:/u/data/* 表示目录/u/data下所有的文件 /u/data/*ab 表示目录/u/data下所有以ab字母结尾的文件 /u/data/*.c 表示目录/u/data下所有以.c结尾的文件(2)? 问号:匹配一个任何字符或数值, 但不含符号“.” 例如:/u/data/? 表示目录/u/data下只含一个字母的文件 /u/data/f?b 表示目录/u/data下以f字
4、母开头、以b字母结尾而且只含 三个字符的文件(3) :在方括号中,可以是任何字符或数值序列。 A它可以匹配方括号中所包含的任何一个字符。 例如:abdf 等于或a、或b、或d、或f B。在方括号里面,由小横杠隔开的一对字符或数值,可以与这对字符或数值给 出的范围中任意字符或数值匹配。 例如:a-d 等于abcd 1-6 等于123456 C在方括号里面,字符“!”表示不包含。 例如:!A-Z 等于不含从A至Z的大写字母注意:目录名字中不应包含下列字符中的任何一个:* ?与 ,如果在目录中使用了这些字符,那么在按照指定字符串查找与之相匹配的名字时,可能出现无限循环。8.1.1.4使用引号 对sh
5、ell来说,引号的作用是删除特殊字符的特殊含义。Shell程序中的特殊字符有: * ? # $ 要使这些字符失去在shell中的特殊意义,需要某些形式的引用。引用方式有三种:(1)单引号“”把特殊字符括起来。 在单引号中引用的全部字符,都将失去它的特殊意义。 例1:在键盘上输入下列信息: aaa=testing echo Parameter $aaa is $aaa 将显示结果为:Parameter $aaa is $aaa 例2:在键盘上输入下列信息 aaa=testing echo Parameter $aaa is $aaa 将显示结果为:Parameter $aaa is testin
6、g 结果表明:单引号中引用的字符$,已经失去了它的特殊意义(2)使用双引号“”把特殊字符括起来。在双引号中引用的全部字符,除特殊意义的字符$、$(command)、”外,其它字符都将失去它的特殊意义。 例3:在键盘上输入下列信息 aaa=testing echo “Parameter $aaa is $aaa” 将显示结果为:Parameter $aaa is testing 结果表明:双引号中引用的字符$,保留它的特殊意义(3)特殊字符前使用反斜杠“”,它的作用是删除特殊字符的特殊含义,将它变成普 通字符。 例4:在键盘上输入下列信息 aaa=testing echo Parameter $
7、aaa is $aaa 将显示结果为: Parameter $aaa is testing 单引号内的符号$失去了它的特殊意义。8.1.1.5标准输入输出 对于绝大多数的shell命令来说,从终端上输入还是从文件中输入,输出到终端还是输出到文件中,都无关紧要,命令的功能不变。因此,shell命令既可以在终端上使用,也可以在管道中使用。只有极少数的几个命令与它们的输入输出方式有关(即输入输出方式不同,它们的作用也不同)。在执行一个命令的时候,通常需打开三个文件:标准输入(standard input)、标准输出(standard output)、诊断输出(diagnostic output)。诊
8、断输出也称标准出错输出(standard),它存放着命令执行过程中出现的出错信息。每个文件都有一个相应的数字,称为文件的描述符。按照约定: 文件 文件描述符 标准输入 0 标准输出 1 诊断输出 2 通常,三个文件的初始状态都与终端相连(0号描述符是键盘,1号和2号描述符是终端屏幕),在shell中,这三个文件都可以脱离初始状态,进行重新定向。1。输入重新定向符 符号 表示输入重新定向符。通过符号 可将命令所需要的信息从标准输入设备定向到某一个文件。 例如:mail 命令所需的信息来自于键盘,现将它定向到文件file # mail 用户名 与 表示输出重新定向符。在标准输出的情况下,如果原来的
9、文件有内容,使用重新定向输出符 后,原有内容被新的内容所替代;若使用重新定向输出符 ,则新的内容将追加到原有内容的后面。 例如:敲入命令行: # date file 表示把命令date的结果输出重新定向到文件file,并将文件file内原来的内容冲掉。 上面的两种定向输出,都是假定原有文件已经存在的情况。如果定向符后面是一个新的文件名,那么Shell将建立这个文件。 例如:abc表示建立一个长度为零,名字为abc的文件3错误重新定向符 符号2 与2表示错误输出重新定向符。执行unix系统命令时所产生的诊断输出,通常被定向到文件描述符2。 例如:cc test.c 2err 在这个命令行中,cc
10、是C语言的编译命令,test.c是C语言编写的源程序。2是标准错误输出的文件描述符。用cc命令对test.c进行编译过程中出现的错误信息,通常放在标准错误输出文件中。这个命令行,把标准错误输出文件重新定向到文件err。其结果是把错误信息附加(appends)到了err文件的尾部,在使用重新定向符时应特别注意,文件描述符与重新定向符之间不能有空格或制表符,比如命令行:2 中的数字2与符号之间不留空格。如果两个符号之间出现了空格或制表符,文件描述符就有可能被shell视为命令的一个参量。8.1.1.6命令行和管道线 在unix系统中,可以若干命令连用,而每个命令之间由竖线“|”(称为管道符)隔开。
11、对于这样使用的命令序列,我们称它为管道线(pipeline)。在管道线中,一个命令的输出(命令产生的结果),正是下一个命令的输入。当然位于管道行的最后一个命令例外。 “过滤器”是在使用管道线时经常遇到的一个概念。所谓“过滤器”是指管道线中的一个命令,过滤器首先读进输入,接着以某种方式将“输入”进行变换(相当于过滤),再将变换结果输出。一个管道线通常由一系列过滤器组成。 Unix系统的过滤器有: cut tr tee pr有关上述命令的使用,请参阅相关文档资料。例如:1who | wc -1 显示系统中注册的用户数。2who | grep bb 显示在系统中注册,且用户名中包含字符串“bb”的用
12、户。3who | grep bb |sort |pr 此行使用了三个管道符。首先查出在系统中注册的用户清单;再从名单中找出名字中含有字符串 “bb”的用户名;然后,把这些用户名按第一个字母顺序排列;最后,以页为单位把排列好的用户清单显示出来。由此,可以看出“过滤器”在管道中的作用。4 date;who|wc -1;log 这一行由三个命令组合使用。把当前日期、在系统注册的用户数附加到log文件的尾部。使用大括号时应当注意,在的后面一定要有一个空格,而在的前面要有一个分号“;”。8.1.1.7命令替换 在shell中,可以把命令行中的命令由后引号()括起来。对于一个由多参量组成的命令行,shel
13、l首先执行后引号中的命令,并且用这个命令的输出(执行这个命令产生的结果),来取代整个表达(即后引号及所包含的命令),这种在一个由若干命令组成的命令行中,由命令输出结果取代这个命令本身的表达方式,称为命令转换。例1:today=date后引号中的date命令的功能是,读出当前系统的时间和日 期。然后,把执行date命令的结果赋给变量today。 进行命令转换时,后引号中可以是一个命令,也可以是多个命令的组合,比如管道线等。例2:users=who | wc l表示将当前系统中注册低用户数,赋给了shell变量 users例3:用户wang敲入命令行: $ logmsg=echo your log
14、in directory is pwd $ echo $logmsg回车后屏幕显示:your login directory is /usr/wang8.1.2 shell中的变量 在shell中,变量是一个字符串值的名字。shell提供了定义变量的机制。某些变量被作为位置参数用在命令行中;而另一些shell变量可由用户或shell给以赋值。8.1.2.1位置参数 位置参数是shell变量的一种。当一个shell过程被调用时,shell将隐含地建立位置参数。在命令行上,位置0处是shell过程的命令名,其位置参数为$1、$2 $9。Shell中规定,在调用一个shell时,它的参数最多不能超过
15、9个。如果参数多于9个,需要用shift命令进行读写操作。8.1.2.2用户定义的变量 在shell中,用户可以自己定义变量。变量名字可以字母组成,也可以由字母和数字混合组成。如果是后者,一定要以字母开头。赋值语句的格式为: 变量名=字符串其中: 变量名 是用户自己定义的变量名字 字符串 作为一个值,赋给“变量名”所表示的变量。注意: 1在shell赋值语句中,等号的左右两侧都没有空格。 2位置参数不能出现在赋值语句的左侧。 3在一个赋值语句中可以有多个赋值,其赋值的顺序是从右到左。例如:MAIL=/usr/mail/wang var =“echo $1 $2 $3 $4” stars = *
16、 * * * * asterisks = $ stars ABC=$stars第一行,把一个文件的路径赋给变量MAIL。第二行,双引号把字符串括起来,允许右侧空格、制表符或分号。var的值是由字 符串“echo”和四个位置参数组成的字符串。第三行,把字符串“* * * * *”赋给变量stars。第四行,变量asterisks的值是“$ stars”,而不是“* * * * *”。第五行,变量ABC的值是“* * * * *”。8.1.2.3 shell定义的变量(环境变量) shell中的变量有两类:一类是由用户设置的变量,它们被称为shell变量。上一节的例子即是用户自己定义的shell变
17、量,变量的名字可以任意确定,它的值也是根据需要设置的;另一类是由shell本身设置的变量,称之为环境变量。它的名字是固定的,它们的值不是随意设置的。 比较可以看出,shell变量是在一个shell活动(如,shell程序运行)内部临时创建的变量,它被用来暂保存信息,当本次shell活动终止时,它就被丢弃了。Shell变量只在shell程序内有效,对其它程序来说是不可见的。所谓环境是对程序的运行而言的,在系统上运行的每一个程序,当它们投入运行时,在内存中都分配有一个专门的区域,这人区域被称为环境。在一个程序运行时,它将继承其父进程(即调用本程序的那个程序,或者是本程序的主程序)的环境副本。这时就
18、要作用环境变量,把配置信息传递给子进程。例如:HOME 表示用户注册主目录名 PATH 表示shell寻找命令的路径 PSI 用来作为屏幕提示的主字符串。8.1.2.4 预先定义的特殊变量 在shell中,下面几个变量具有特殊意义。它们的设置,只能由shell进行,而不能通过用户进行重新设置。 $# 记录传送给shell的参量数,但它不把shell过程自己的名字计数在内。因 此,$#可以给出所设置的位置参数的个数。 $? 包含最后一个执行命令的返回结果。它是一个十进制数字。为零时,表示命 令执行成功。 $ 这个变量表示当前进程的进程号。因为对系统中现有的进程来说,进程号是 唯一的。这个字符串常
19、常被用来为临时文件产生唯一的文件名。8.1.2.5 shell说明1改变目录 cd命令的功能,是把当前目录改变为这个命令变量中指定的那个目录。系统提供的这种手段,可以直接应用到shell程序中来。2. .profile文件 在用户每次向系统注册时,shell都要读该用户的.profile文件。系统中的每个普通用户都有自己.profile文件。超级用户在根下有一个.profile文件,通过它设置shell程序所需的环境变量。3运行标志 在shell中,通过set命令设置某些标志,可以使用户改变shell的功能。 其中标志项有:-a 标志变量,为export命令的使用,修改或建立标记。-e 如果s
20、hell是非交互式的,当一个命令以非零状态返回时将直接退出shell。-f 禁止文件名产生。-h 设置函数命令(即把函数当作命令使用)。-k 把全部的关键字参量放在命令的环境中。-n 读命令,但不执行这个命令。-x:命令执行时,这些命令和它们的参量同时显示在屏幕上。但也有些shell命 令,比如用于循环体的“for”、“while”等并不显示。-v:读输入信息时,输入行在屏幕上显示。对分析输入行的语法错误是非常有用 的。例如:# set -x# echo this is a test回车后,屏幕显示:+echo this is a testthis is a test第一行:echo命令和它的
21、参量全部显示,行首的+号,提示用户检查是否有语句错 误。第二行 echo命令执行的结果。注意:在上述标志前使用加号“+”,表示关闭这个标志;使用减号“-”,表示设置这个标志。8.1.3 运行环境和流向控制8.1.3.1命令运行的环境变量 在shell中,所有的变量及它们的值,都可以认为是命令开始执行时建立起来的运行环境。此外,运行环境还包括这样一些变量,它们中一些是从父进程沿袭下来的变量,另一些是使用命令时,命令行上指定作为关键字参数的变量。 如果shell进程要给它的子进程传送变量,那么这个变量就必须使用export命令进行说明。export命令也叫变量输出命令。 赋值形式为:变量=值 例如
22、:TERM=vt100;export TERM8.1.3.2 shell过程调用和参量传递1. shell调用 shell实际上是一种命令。我们可以按照unix系统提供命令的使用方法来使用它。因此,调用shell有两种方法:(1)sh proc arg 它的含义是:请示系统调用一个新的shell来读proc,方括号中的arg是proc运行所需的选项。 例如: 一个名字叫echo2的shell过程,其文本内容为: for word do echo $word$word done 在提示符下敲入命令行:#sh echo2 abc 屏幕上将显示信息:abcabc 或 sh -v proc arg 其
23、中,-v是执行标志,相当于在过程proc的开始处放了一个命令行:set -v 例如上例给出的shell,在提示下符下敲入命令行:#sh -v echo2 abc 回车,屏幕显示:for worddo echo $word$worddoneabcabc 因此,使用了标志项-v后,它把shell过程的文本及执行这个过程所产生的结果全部显示在屏幕上。同样,还可以设置其它标志项:-x、-e、-u与-n。(2)proc arg 如果proc是一个可执行文件,并且是一个不需编译就可执行的程序,这时,调用shell的方法可以为:proc args2.参量传给shell的过程 当一个命令行从键盘上敲入后,sh
24、ell就对这个命令行进行扫描,并把形如 $n 的字符序列由第n个参量取代。Shell过程的名字计数为 $0。这样的计数方法,就可以直接索引过程的名字,并且可以有9个位置参数。多于9个位置参数的情况,可以用shift命令来处理。 shift命令如果不带任何参量,它的功能是把位置参量左移一位,即$1的值被移出,$2的值取代$1的值,$3的值取代$2的值,依次类推。由此可见,左移后,原来$1的值丢掉了,它不能移到$0的位置。如果这个命令带有参量:shift n ,此处n是一个数字,那么shift所完成的功能是:每次把位置参数左移n位。 例如: #file while test $# !=0 do e
25、cho $* shift done其中第一行: 含有字符“#”,表示注释行。第二行: 循环命令while用于检查判断,当参数的个数 $# 不为0时,继续执行循环体中的命令。 如果使用下面命令调用程序file: file a b c d e 将会显示结果:a b c d e b c d e c d e d e e 结果表明,循环体被执行了5次。从第二次开始,每执行一次,就把$1位置上的参量左移一位。8.1.3.3 shell流向控制所谓流向控制,是指shell过程中的循环、检测、设陷、退出等涉及到shell过程运行走向的一系列操作。相关的几个问题(1) 管道线 管道线是一个包含了一个或多个命令的
26、序列。命令之间由管道符“|”隔开。在一个管道线中,前一个命令的标准输出都是与之相连的后一个命令的标准输入。管道线中的每个命令是独立运行的,shell一直等到最后一个命令执行完成。整个管道线的退出状态(即管道行完成时返回的状态),是管道行中最后一个进程的退出状态。(2) 命令清单 命令清单是由一个或多个管道线构成的序列。管道线之间可以是符号“;”、“&”、“&”、“|”。命令清单可以由“;”或“&”来结束。命令清单中如果两个管道线之间是用分号隔开的,将按管道线的前后顺序执行,也就是说,shell要等待一个管道线执行完毕才能读下一个管道线。如果两个管道线之间是由“&”隔开的,那么前一个管道行异步地
27、在后台执行。 例如:nohup cc prog.c &其中cc是unix操作系统上所配的c语言的编译器。prog.c是用c语言编写的源程序。由于这个命令行用“&”结束,因此在编译器对源程序prog.c进行编译过程中,用户敲入中断键或键入quit命令退出系统,既不能中断、也不会退出编译的进行。(3)nohup命令 其功能是运行一个命令,并且不受任何挂起(hangups)和退出的影响。 命令行格式: nohup command arguments 其中:command 代表要运行的命令的名字 arguments 表示参量。 注意:使用这个命令时,如果用户没有对输出进行重新定向,那么,它将把输出结果
28、存放到nohup.out文件中;如果用户在当前目录下,不具有写操作权限,那么nohup命令的输出就被重新定向到 $HOME/nohup.out。(4)符号&和|符号 & 使一些程序能在后台运行,究竟哪些程序可以在后台运行,要视情况而定。因此,“&”的使用也受到一些限制。特别是在系统负载比较重时,不宜启动过多的后台进程。符号&(and-if)与|(or-if)的作用是使管道线有条件地执行。它们在命令行上操作的优先级是相同的,并且低于操作符 & 和 | 的优先权。|的格式为: cmd1|cmd2 其中cmd1、cmd2分别代表命令1和2。命令行的意义是,先执行命令cmd1,并对这个命令执行后的返回
29、状态进行检测。只有在cmd1运行失败时(返回状态非零时认为运行失败,为零时表示运行成功)才执行命令cmd2。操作符|在这个命令行中的作用是进行条件判断,相当于下列语句: if cmd1 test $? !=0 then cmd2 fi&的格式: cmd1&cmd2 其中 &的作用是进行一个与 |互补的检测。其作用是:只要第一个命令cmd1执行成功(返回状态为零),就执行第二个命令cmd2。 例如:cmd1&cmd2&cmd3&cmdn 在这个程序中,前一个命令执行成功,总是后一个命令执行的必要条件。(5)小括号和大括号 一个管道行中的简单命令,可以由小括号或大括号括起来的命令清单进行替换。换名
30、话说,命令清单由小括号或大括号括起来之后,可以用来取代管道行中的一个简单命令。被括起来的全部命令的输出构成一个流(stream),这个流作为该管道行中下一个命令的输入。 命令1 参量;命令2 参量;|命令常用的几个语句介绍几个与shell过程循环有关的语句。(1) if语句 在shell中,if语句用于表示条件的结构中,最简单的使用为: 形式一: if command-list1 then command-list2 fi 注意: fi和if配对使用,fi总是放在这个条件语句的最后一行,表示if命令的结束。 command-list表示一个命令清单。如果命令清单1执行成功,接着执行单2 形式二:if command-list1 then command-list2 else command-list3 fi 表示: 如果命令清单1执行成功,接着执行命令清单2,然后退出;否则转去执行命 令清单3。 形式三:if command-list1 then command-list2 elif command-list3 then command-list4 else command-list5fi 其意义为:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1