1 / 83

第三讲 shell 程序设计

第三讲 shell 程序设计. 3.1 概述. shell 是 UNIX 系统用用户与操作系统交互的最基本工具,实际上 shell 除了有命令解释执行的功能外,还具备有其他的功能,如:. 系统环境的设置. 输入输出的重新定向. shell 程序语言的设计等。. 3.1 概述.

Download Presentation

第三讲 shell 程序设计

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第三讲 shell 程序设计

  2. 3.1 概述 shell是UNIX系统用用户与操作系统交互的最基本工具,实际上shell除了有命令解释执行的功能外,还具备有其他的功能,如: 系统环境的设置 输入输出的重新定向 shell程序语言的设计等。

  3. 3.1概述 在UNIX系统中使用shell程序设计,可以完成比较复杂并且自动执行的任务。UNIX系统上的shell程序在本质上是一种解释执行的脚本语言,使用的元素是UNIX系统的命令集,它与windows系统中的bat批处理文件原理相同,但是比批处理文件更强大,也更灵活。

  4. 举例 3.1 概述 # append.sh case $# in 1 ) cat >> data.txt;; 2 ) cat $1 >> $2 ;; * ) echo “Incorrect usage ! ” ;; esac

  5. 举例 3.1 概述 cd $HOME for dir in cc work do echo “…. In $dir….” cd $dir for file in *.[c] do ls –l $file done cd done

  6. 3.2 Shell程序的执行方式 Shell程序有多种执行方式,比如,我们建立一个比较简单的shell程序脚本,文件保存命名为 test.sh,内容如下: date who ps 执行这个test.sh可以有多种方式。 1)将test.sh作为shell命令的执行参数来完成该shell的执行: $ sh test.sh 2)利用输入输出的重定向方式 $ sh <test.sh 3)直接执行该shell程序,但首先要保证该shell程序具备可执行的权限,可以用chmod来修改: chmod a+x test.sh, 之后在命令行执行它 $ test.sh

  7. 3.3 Shell程序的变量 • 如果shell程序只能简单地执行一些命令,那shell的功能无疑是非常弱的,幸运的是,shell程序被设计为可以支持变量的使用,比如定义变量,应用变量的值等等。这使得shell程序具有异常强大的功能。需要注意的是,shell的变量只有字符串型,在shell程序中出现的数值计算都是基于字符串类型来完成的。 • Shell有以下几种基本类型的变量: • shell定义的环境变量 • 用户定义的变量 • 位置参数 • 预定义变量

  8. 3.3 Shell程序的变量:变量赋值 1)shell中的变量和变量赋值 shell 变量定义由字母开始,可以包含数字,字母和下划线,例如var1, username,pass_word等。 变量的赋值可以在程序运行中进行,也可以在变量定义时进行,例如UNIX=“SYSTEM V”,如果字符串中间没有空格和制表符,则可以不要双引号。 值得注意的是B-shell中等号=的两边是不允许有空格的。

  9. 3.3 Shell程序的变量:变量访问 2)shell中变量的访问和参数替换 在shell程序中,或者是shell命令中,使用操作符$来对shell变量进行访问。例如,要显示某个变量时,可以输入: $ echo $UNIX (系统将会显示SYSTEM V ) 在某些场合下,为了明确表示对shell变量的引用,可以用花括弧{ }或者双引号将变量括起来,例如: $ echo ${UNIX} $ echo ${UNIX}Aaaaaa $ echo “$UNIX” is very good SYSTEM V SYSTEM VAaaaaa SYSTEM V is very good

  10. 3)shell中引号的说明: 单引号‘’、 双引号“”、 反引号` (a)单引号’ :使用单引号时,shell将一对单引号之间的内容看成是纯粹的字符串信息,一对单引号之间可以包含更多的单引号。 you=”kkk” echo ‘this is just a ‘test’, can $you tell me the time ?’ 将会显示this is just a ‘test’, can $you tell me the time ?, 它不会将$you替换成“kkk“, 同时‘test’也是作为字符串内容来处理的。 (b)双引号“ : 它将双引号之间的特殊字符作为shell中的含义来解释。 $ file=unixshell $ echo “the content of ‘date’ is in $file” 这个例子将会显示 the content of wed Aug 16 16:20:12 is in unixshell,这个例子中,’date’被解释成了当前时间的返回值,$file被解释成了unixshell字符串。 (c)反引号`用它来赋值时,表示变量中保存的是执行对应命令的结果。 name=`whoami` echo $name 这个时候显示的不是字符串whoami,而是执行字符串whoami的返回结果,当然,要先保证字符串是一个合法的命令。

  11. 4)变量的定义域 同其他的编程语言如C,pascal一样,shell的变量也有局部变量和全局变量的区别。通常在一个shell程序中,通过形如var1=abc方式定义的都是局部变量,只能在该shell程序的进程中起作用,要定义全局变量,需要在局部变量定义之后使用export 命令来将这个变量声明为全局的: export $var1 以下面的例子var.sh,我们来说明全局变量和局部变量的区别和使用 $ var1=csu $ echo $var1 $ sh $ echo $var1 $ exit $ echo $var1 $ export $var1 $ sh $ echo $var1 第一个echo显示的是 csu,这是通常的用法 第三行,调用sh进入一个新的shell进程 第四行的echo显示为空,因为var在这个进程中并没有进行定义 第五行,调用exit退出新建的shell回到原来shell的进程中 第六行的echo又能够正常显示了 第七行调用export,将var1定义为全局的,这样在新建的shell中,var1也能访问, 最后一行显示出csu

  12. 3.3 Shell程序的变量:环境变量 5)环境变量 shell在开始执行时就已经定义了一些和系统的工作环境有关的变量,这些变量用户还可以重新定义,常用的shell环境变量有:

  13. 3.3 Shell程序的变量:环境变量 HOME:用于保存注册目录的完全路径名。 PATH:用于保存用冒号分隔的目录路径名,shell将按PATH变量中给出的顺序搜索这些目录,找到的第一个与命令名称一致的可执行文件将被执行。 TERM:终端的类型。 UID:当前用户的标识符,取值是由数字构成的字符串。 PWD:当前工作目录的绝对路径名,该变量的取值随cd命令的使用而变化。 PS1:主提示符,在特权用户下,缺省的主提示符是“#”,在普通用户下,缺省的主提示符是“$”。 PS2:在shell接收用户输入命令的过程中,如果用户在输入行的末尾输入“\”然后回车,或者当用户按回车键时shell判断出用户输入的命令没有结束时,显示这个辅助提示符,提示用户继续输入命令的其余部分,缺省的辅助提示符是“>”。

  14. 3.3 Shell程序的变量:位置变量 6)Shell中命令的位置变量 位置参数是一种在调用shell程序的命令行中按照各自的位置决定的变量,是在程序名之后输入的参数。位置参数之间用空格分隔,shell取第一个位置参数替换程序文件中的$1,第二个替换$2,依次类推。$0是一个特殊的变量,它的内容是当前这个shell程序的文件名,所以,$0不是一个位置参数,在显示当前所有的位置参数时是不包括$0的。 #listargs.shargv1 argv2 argv3 argv4 $0 $1 $2 $3 $4

  15. 3.3 Shell程序的变量:预定义变量 预定义变量和环境变量相类似,也是在shell一开始时就定义了的变量,所不同的是,用户只能根据shell的定义来使用这些变量,而不能重定义它。所有预定义变量都是由$符和另一个符号组成的,常用的shell预定义变量有:

  16. 3.3 Shell程序的变量:变量替换 7).Shell中的变量替换 在shell编程中,有时候会遇到这种情况,一个变量在尚未赋值的时候,就被程序进行了输出处理,这样输出的变量将会得到一个空字符串的结果。为了避免这种情况的发生,shell中引入了变量替换的概念,在变量没有赋值的时候可以用一个预先定义的字符串来替换。 替换的形式有三种,列举如下: $ {var:-word}表示如果var已经被赋值,则取它的值,否则取word的值,但var不改变。 $ {var:=word} 表示如果var已经被赋值,则取它的值,否则取word的值,同时将word赋给 var。 $ {var:+word} 表示如果var已经被赋值,则取它的值,否则var变量置为空。

  17. 3.4 test命令的使用 在shell中经常要对某些变量的值进行判断来决定分支程序的走向,如同C中使用 if( a == 0) 一样。Shell中通过test命令来完成这个功能。 test的格式表示为: test expre 或者 test [expre] test命令的执行结果是,如果表达式为真,则返回真值0,否则返回非0的假值。 test命令可以对文件,字符串内容,整数n等变量进行测试。

  18. 3.4 test命令的使用 1)对文件特性的测试 语法: test [-dfrwxs] file -e文件名:如果文件存在则为真 -r文件名:如果文件存在且可读则为真 -w文件名:如果文件存在且可写则为真 -x文件名:如果文件存在且可执行则为真 -s文件名:如果文件存在且至少有一个字符则为真 -d文件名:如果文件存在且为目录则为真 -f文件名:如果文件存在且为普通文件则为真 -c文件名:如果文件存在且为字符型特殊文件则为真 -b文件名:如果文件存在且为块特殊文件则为真

  19. 3.4 test命令的使用 例如: $ test –d /home/user && echo “directory exists” 判断/home/user 是否为一个目录文件,如果为真(&&)则执行echo进行显示 $ test –x /home/user/sh1.sh || echo “sh1.sh dos not exist or is not runnable !” 判断文件/home/user/sh1.sh是否可执行,如果为假(||)则执行echo进行显示

  20. 3.4 test命令的使用 2)对字符串内容的测试 语法: test s(字符串s为有值时返回真,为空则返回假) test -zs与test s 相反,为空时返回真,不空则返回假 test s1 = s2当字符串s1和s2相等时返回真,不相当则返回假 test s1 != s2与test s1=s2相反。 例 x1=“005” x2 =5,进行字符串测试 #test “$x1” = “$x2” #echo $? 系统将显示0, 结果为假值,表示x1和x2不相等

  21. 3.4 test命令的使用 3)对于整数n的的测试 格式 test n1 [-eq/ne/it/ie/gt/ge] n2 它们分别表示n1和n2之间 相等 /不相等 /n1<n2/n1<=n2 /n1>n2 /n1>=n2 时返回真值。 例 x1=“005” x2 =5,进行数字式测试 #test “$x1” -eq “$x2” #echo $? 系统将显示1, 结果为真值,表示数字x1和数字x2相等

  22. 3.5 条件控制语句 在结构化的程序设计中,三种基本的语句结构是顺序结构,分支结构,循环结构。其中的分支结构,在shell中常用if和case语句来实现。 1)if语句 if语句的分支可以有 无分支条件语句,二分支条件语句,多分支条件语句。 无分支条件语句格式如下: if [condition] then 命令1 命令2 … 命令n fi 当条件condition为真时,执行then后面的所有命令,condition为假则执行fi后面的语句。

  23. 3.5 条件控制语句 1)if语句 例:edit.sh if [ $#=1 ] then cp $1 $HOME/user1 fi vi $1 exit 0

  24. 3.5 条件控制语句 多分支结构:分支大于2的条件语句。 if [condition1] then elif [contition2] then elif [condition3] then … else command_n fi 二分支条件语句: 格式为 if then else 结构 if [condition] then 命令1 命令2 else. 命令n fi

  25. 3.5 条件控制语句 例:假设一个连续运行系统,将建立错误记录文件errorfile 并不断写入错误信息。现在要求编写一个shell程序来产生定时错误日志文件datelog,能在datelog 中体现每个时间段中的错误信息 # checkerr.sh To check error information with time stamp !!! date >> datelog if test –r errorfile then cat errorfile >> datelog rm errorfile else echo “No error occurs during this hour!“ >> datelog fi

  26. 3.5 条件控制语句 2)case语句 可以实现多选一的控制结构 case语句的语法为: case word in 模式1 ) 命令 ;; 模式2 ) 命令 ;; 模式3 ) 命令 ;; esac 注意,在case中,每个命名命令的结束用;;表示模式匹配已经完成,不再匹配其他的模式,相当于C中的break。

  27. 3.5 条件控制语句 例:编写一段shell程序,根据执行时获取的当前时间显示不同的问候信息 • # hello.sh • hour = `date +%H` • case $hour in • 0[1-9] | 1[01] ) echo “Good morining !!” ;; • 1[234567] ) echo “Good afternoon !!” ;; • ) echo “Good evening !! ” ;; • esac

  28. 例:利用shell的位置变量参数编写一个shell,当只有一个参数时,从键盘输入文本保存到data.txt中,当有两个参数时,将参数1代表的文件内容添加到参数2表示的文件,其他情况则给出错误提示信息例:利用shell的位置变量参数编写一个shell,当只有一个参数时,从键盘输入文本保存到data.txt中,当有两个参数时,将参数1代表的文件内容添加到参数2表示的文件,其他情况则给出错误提示信息 3.5 条件控制语句 # append.sh case $# in 1 ) cat >> data.txt;; 2 ) cat $1 >> $2 ;; * ) echo “Incorrect usage ! ” ;; esac

  29. 3.6 循环语句 shell中的循环有for和while两种循环方式。 1)for的语法格式为: for var in list-of-vars do command1 command2 … commandn done for的语法说明为:shell程序扫描变量列表list-of-vars,将其中的每一个字依次存放在var中,并执行do和done之间的语句。如果list-of-vars中有n个字,则这个for循环将执行n次。

  30. 3.6 循环语句 在需要的时候,也可以进行for循环的嵌套。 见下面的例子: cd $HOME for dir in cc work do echo “…. In $dir….” cd $dir for file in *.[c] do ls –l $file done cd done

  31. 3.6 循环语句 2)while循环 while - do - done结构 while循环中,只要循环条件为真就一直循环下去。 格式: while [condition] do command1 command2 ….. done

  32. 3)until循环 until-do-done until循环和while循环类似,所不同的是until循环只要循环条件为假,就一直执行循环体。 格式: until [condition] do command1 commandn done 如果第一次执行时,循环条件condition就为真,那循环体将得不到执行。 同时还要注意,必须在程序中设置条件condition为真的因素,否则循环将一直进行下去,从而进入了死循环。 3.6 循环语句

  33. 3.6 循环语句 例:编写shell程序一次性创建若干个新文件,如file1, file2, file3. . . . . . file10 两个相关命令 touch 命令,改变文件的访问和修改时间 格式: touch [option][time] filename [option] -a 只修改文件的访问时间 -m 只修改文件的修改时间 当指定文件filename不存在,则创建一个具有默认权限和当前时间的新文件

  34. 3.6 循环语句 例:编写shell程序一次性创建若干个新文件,如file1, file2, file3. . . . . . file10 两个相关命令 expr 命令,对shell变量进行算术运算的操作,因为shell变量都是字符型,进行算术运算必须使用expr命令 shell中错误的算术运算: #count = 9 #count = $count + 11 #echo count shell中正确的算术运算: #count = 9 #count = `expr $count + 11` #echo count 系统将显示:9+11 系统将显示:20

  35. 3.6 循环语句 例:编写shell程序一次性创建若干个新文件,如file1, file2, file3. . . . . . file10 # genfiles.sh NUMBER = 1 While [ $NUMBER –lt 11] do touch file$NUMBER NUMBER = `expr $NUMBER + 1` done

  36. break用于立即终止当前循环的执行,而contiune用于不执行循环中后面的语句而立即开始下一个循环的执行。这两个语句只有放在do和done之间才有效。break用于立即终止当前循环的执行,而contiune用于不执行循环中后面的语句而立即开始下一个循环的执行。这两个语句只有放在do和done之间才有效。 3.7无条件控制语句break和continue

  37. 在shell中还可以定义函数。函数实际上也是由若干条shell命令组成的,因此它与shell程序形式上是相似的,不同的是它不是一个单独的进程,而是shell程序的一部分。函数定义的基本格式为:在shell中还可以定义函数。函数实际上也是由若干条shell命令组成的,因此它与shell程序形式上是相似的,不同的是它不是一个单独的进程,而是shell程序的一部分。函数定义的基本格式为: functionname {    若干命令行 } 3.8 函数

  38. 函数使用:1、调用函数之前,必须先定义函数。2、函数的参数的传递:functionname para1 para2 ….  3、在函数内部参数的读取: $0-$9 , $@(所有参数) $#(参数总个数)4、函数的返回值:可能使用return命令返回数字值;要返回字符串值,可以字符串保存在一个全局性的变量中,该变量在函数结束后能被外界使用;如果没有使用return命令,则函数返回值是函数中最后执行的一条命令的退出状态码。5、变量使用:函数内部声明的变量默认为全局变量,使用local关键字声明的变量为局部变量(如 local var=“var”)。如果局部变量与全局变量同名,则在函数内部局部变量覆盖全局变量。6、返回值的获取,当执行完函数后,函数的返回值被存放在$?中,可以通过它来获取函数的返回值。 3.8函数

  39. 举例 #HELLO.sh function hello( ) {     echo “hi” } hello echo $? 执行结果如下:# sh hello.shhi 3.8 函数

  40. 举例 #This is a example for testing the return value of function function fun() { return 10} fun echo $? exit 0 3.8 函数 执行结果如下:# sh fun.sh10

  41. 举例 #funsample1.sh function add( ) {     declare -i sum     sum=$1+$2     return $sum} add 10 20 echo $? 执行结果如下:# sh funsample1.sh30 3.8 函数

  42. 举例 function find_file(){        if [ $# -lt 1 ];then                return 1;        fi       if [ find -name $1 –print2>/dev/null ]        then    :        else                echo "File $1 not found"        fi} 3.8 函数

  43. 举例 #_MAIN_        if [ $# -lt 1 ];then                echo "Usage: $0 filename"                return 1;        fi        for loop in $@        do                find_file $loop        done 3.8 函数

  44. 举例 #_MAIN_        if [ $# -lt 1 ];then                echo "Usage: $0 filename"                return 1;        fi        for loop in $@        do                find_file $loop        done 3.8 函数

  45. 举例 #test1.sh function hello() { echo “hi” } #test.sh #注意.后面要有一个空格 . test1.sh hello 执行结果: hi 3.8 函数

  46. 在shell中有两种命令分组的方法:“()”和“{}”,前者当shell执行()中的命令时将再创建一个新的子进程,然后这个子进程去执行圆括弧中的命令。当用户在执行某个命令时不想让命令运行时对状态集合(如位置参数、环境变量、当前工作目录等)的改变影响到下面语句的执行时,就应该把这些命令放在圆括弧中,这样就能保证所有的改变只对子进程产生影响,而父进程不受任何干扰;{}用于将顺序执行的命令的输出结果用于另一个命令的输入(管道方式)。当我们要真正使用圆括弧和花括弧时(如计算表达式的优先级),则需要在其前面加上转义符(\)以便让shell知道它们不是用于命令执行的控制所用。在shell中有两种命令分组的方法:“()”和“{}”,前者当shell执行()中的命令时将再创建一个新的子进程,然后这个子进程去执行圆括弧中的命令。当用户在执行某个命令时不想让命令运行时对状态集合(如位置参数、环境变量、当前工作目录等)的改变影响到下面语句的执行时,就应该把这些命令放在圆括弧中,这样就能保证所有的改变只对子进程产生影响,而父进程不受任何干扰;{}用于将顺序执行的命令的输出结果用于另一个命令的输入(管道方式)。当我们要真正使用圆括弧和花括弧时(如计算表达式的优先级),则需要在其前面加上转义符(\)以便让shell知道它们不是用于命令执行的控制所用。 3.9 命令分组

  47. shell程序是一种解释性语言,它的执行是逐行进行的,程序中是否有语法错误,不执行到那一行系统是无法知道的。C,pascal等高级语言是有编译过程的,程序中的语法错误在编译阶段就能检测出来,因此比shell更容易调试 shell程序通常有三种调试方法: 3.10 Shell程序调试 1)交互式调试 shell程序中使用的命令都能在命令行中运行,所以对于一些不很熟悉的命令和语法可以先用命令进行验证,然后再编写到shell程序中,这种调试方法称为交互式调试,也是最简单的一种调试方法。

  48. 2)在编辑过程中不断调试执行所编辑的shell程序2)在编辑过程中不断调试执行所编辑的shell程序 在UNIX系统中可以打开多个工作窗口。我们可以在一个窗口中用vi等编辑器进行编辑,然后在另一个连接窗口中执行该shell程序,这样可以随时观察到已经编写的部分是否正确。最终完成这个shell程序的编写。 3.9 Shell程序调试 3)用shell程序提供的跟踪功能进行调试 shell程序可以使用 -v -x 选项对shell程序进行跟踪 -v:当读入shell输入行时把它们显示出来,完成详细跟踪。Shell程序在完成这段程序执行时首先逐行读入执行的命令,并在标准输出上显示该命令要执行的实际内容,然后执行该命令。如果没有语法错误,执行将一直进行下去直到完成shell的执行。 -x:执行命令前先把命令和它们的参数显示出来

  49. 假设有这么一个简单的shell,叫test1.sh date echo $PATH 我们用-v参数来调试, 执行sh -v test1.sh那么输出就应该是: date Mon Sep 8 9:55:01 Linux9 2003 echo $PATH /usr/bin:/usr/ucb/bin:/home/user1 shell在执行date前先显示该命令然后显示date的执行结果,接着显示echo $PATH以及它的执行结果。 3.9 Shell程序调试 如果用-x参数来执行这个shell,执行 sh -x test1.sh则系统的输出将是: +date Mon Sep 8 9:55:01 Linux9 2003 +echo /usr/bin:/usr/ucb/bin:/home/user1 /usr/bin:/usr/ucb/bin:/home/user1 date这一行没有参数,所以只显示命令 echo这一行有参数$path,被直接替换成了参数的值。

  50. 3.9 Shell程序调试 在调试一个比较大的shell时,没有必要对整个shell程序都进行跟踪,可以只对其中较为负责的部分进行跟踪,这时可以通过 set –v ……… set +v或者set –x …………set +x来把需要跟踪的部分包含进来。

More Related