创建和执行shell程序 变量 位置参数 内部变量 特殊字符 表达式的比较 重复语句 条件语句 杂项语句 函数 第八章Linux下的Shell编程 创建和执行shell程序 变量 位置参数 内部变量 特殊字符 表达式的比较 重复语句 条件语句 杂项语句 函数
Linux中的各种shell shell名称 描述 位置 ash 一个小shell(和sh类似) /bin/ash ash.static 一个不依靠软件库的ash版本 /bin/ash.static bash Bourne Again Shell /bin/bush bush2 Bourne Again Shell的新版本 /bin/bush2 bsh ash的一个符号链接 /bin/bsh csh C shell,tcsh的一个符号链接 /bin/ash ksh 公共域 受限制的shell(针对网络操作) /usr/bin/rsh sh bash的一个符号链接 /bin/sh tcsh 和csh兼容的shell /bin/tcsh zsh 一个和csh,ksh和sh兼容的shell /bin/zsh
8.1创建和执行shell程序 进入系统时需要设置一些别名,可以用文本编辑程序(例如vi)把这些别名放在一个文件中,然后执行这个文件,而不需要每次进入系统是都要打入所有的别名。 这是一个为此目的而创建的(bash)示范文件myenv,内容如下: alias ||=’ls-l’ alias dir=’ls’ alias copy=’cp’ chmod命令来设置mynev为可执行的 #chmod +x mynev 在执行mynev前,要确保另一个条件,即mynev文件必须在查找路径中。执行如下命令可以获得查找路径。 # echo $PATH
如果放置mynev的文件的目录不在当前的查找路径中,那么必须把这个目录加到查找路径中。 就可以从命令行中就象执行Linux命令一样来执行mynev文件。 # mynev 提示:必须确保shell程序的第一行是以磅符(#)开头,磅符告诉shell本行为注释。在磅符后必须由叹号(!),叹号告诉shell运行叹号之后的命令并用文件的其余部分作为输入。这是所有shell脚本惯用的做法。
8.2 变量 三种变量类型:环境、内部和用户。 环境变量是系统的一部分,不必去定义它们。可以在shell程序中使用它们,某些变量(如PATH)还能在shell程序中加以修改。 内部变量是由系统提供的。与环境变量不同,不能修改它们。 用户变量是在编写shell过程中定义的。可以在shell程序中任意修改它们。 Shell编程和其他编程语言的重要不同是,在shell编程过程中的变量是非类型性质的,也就是说不必指定变量是数字还是字符串。
给变量赋值 命令 环境 locunt=0 pdksh和bush set locunt=0 tcsh 命令 环境 命令 环境 locunt=0 pdksh和bush set locunt=0 tcsh 在pdksh和bush 下,必须确保等号“=”前后没有空格 命令 环境 my name=Sanjiv pdksh和bush set name=Sanjiv tcsh 如果字符没有嵌入空格,可以利用上面的命令;如果字符串有嵌入的空格,可以执行如下的赋值语句: 命令 环境 my name=’Sanjiv Guha’ pdksh和bush set name=’Sanjiv Guha’ tcsh
访问变量值 可以通过变量名前置以$(美元符)来访问变量的值。假如变量名为var,利用$var就能访问这个变量。 如要把var的值赋给变量lcount,可以执行如下命令: 命令 环境 lcount=$var pdksh和bush set lcount=$var tcsh
8.3位置参数 当编写一个带有若干参数的shell脚本时,可以从命令行或从其它的shell脚本调用它。这些选项是通过Linux作为位置参数来提供给shell程序的。位置参数有系统给出的专用名。存放在变量中的第一个参数名为1(数字1),在程序内可以用$1来访问,存放在变量中的第二个参数名为2,在程序中可以利用$2来访问它,以此类推。例如,shell程序mypgm要求两个参数(如名和姓),可以只用一个参数(名)来调用shell程序。但是,不能只利用第二个参数(姓)来调用shell程序。
这里有一个shell程序的mypgm1,只带了一个参数(名字),并在屏幕上显示这个名字: #Name display program if [ $# -eq 0 ] then echo “Name not provided” else echo”Your name is $1” 执行: #. Mypgm1 得到输出: Name not provided 但是,如果执行mypgm1如下: #. mypgm1 sanjia 则得到输出:Your name is sanjia
8.4 内部变量 部分内部变量: 变量 作用 $# 传给shell程序的位置参数的数目 变量 作用 $# 传给shell程序的位置参数的数目 $? 最后命令的完成码或在shell程序内所执行的shell 程序 $0 shell程序的名称 $* 调用shell程序示所传送的全部变元的单字符串
echo “Number of parameters is ”$# echo “Program name is ”$0 mypgm2的示范例子: #my test program echo “Number of parameters is ”$# echo “Program name is ”$0 echo “Parameters as a single string is ”$* 命令行中执行mypgm2如下: #. mypgm2 sanjia guha (点(.)是告诉shell执行mypgm2文件的一种方法 ) 将得到如下的结果: Number of parameters is 2 Program name is 2 Parameters as a single string is sanjia guha
8.5特殊字符 字符 说明 $ 指出shell变量名的开始 | 把标准输出通过管道传送到下个命令 # 标记注释开始 & 在后台执行进程 字符 说明 $ 指出shell变量名的开始 | 把标准输出通过管道传送到下个命令 # 标记注释开始 & 在后台执行进程 ? 匹配一个字符 * 匹配一个或几个字符 > 输出重定向操作符 < 输入重定向操作符 >> 输出重定向操作符{添加到文件} << 跟在输入结束自符串后(HERE)操作符 [] 列出字符的范围 [a-z] 意指a到z的全部字符 [a,z] 意指a或z字符 .filmname 执行(“源”)filename文件 空格 在两个字之间的间隔符 有些特殊字符应进行专门的解释。这些特殊字符是:双引号、单引号、反斜杠、以及反引号。
8.5.1双引号 在字符串含有嵌入的空格时,必须把字符串括起来,写成: 命令 环境 x=”abc def” pdksh和bash 命令 环境 x=”abc def” pdksh和bash set x=”abc def” tcsh 双引号可以解析字符串内的所有变量。这是一个有关pdksh和bash的例子: var=”test string” newvar=”Value of var is $var” echo $newvar 下面是有关tcsh的相同例子: set var=”test string” set newvar=”Value of var is $var” 执行上面的三行shell程序,可得到如下的结果: Value of var is test string
8.5.2单引号 利用单引号把字符括起来,以阻止shell解析变量。在下边的例子中,把前面的双引号改为单引号: pdksh和bash: var=’test string’ newvar=’Value of var is $var’ echo $newvar tcsh: set var=’test string’ set newvar=’Value of var is $var’ 执行包括上面三行的shell程序,可得到如下的结果: Value of var is $var 正如我们所看到的,var变量没有被解析。
8.5.3 反斜杠 在某个字符前利用反斜杠可以阻止shell 把后面的字符解释为特殊字符。例如要把$test的值赋给变量var。输入如下命令: 命令 环境 var=$test pdksh和bash set var=$test tcsh 那么存放在var中的值将是一个空值。这是因为shell以变量test来解析$test,而test未赋给任何值,所以var 为空。应该用如下的命令把$test正确的存放在var中。 命令 环境 var=\$test pdksh和bash set var=\$test tcsh 在$符之前的反斜杠用来告知shell如同任何其他普通的字符一样来解释$,因而$没有任何特殊的含义。
8.5.4反引号 利用反引号(`)通知shell执行由反引号定义的字符串。当需要把执行命令的结果存放在变量中时,就可以在shell程序中利用反引号。例如,要统计当前目录下一个文件中test.txt有几行并把结果存在叫做var的变量中时,可以用下边的命令: 命令 环境 var=`wc -l test.txt` pdksh和bas set var=`wc -l test.txt` tcsh
8.6表达式的比较 8.6.1 pdksh和bash 1.字符串比较 下面操作符可以用来比较两个字符串表达式: = 比较两个字符串是否相等 = 比较两个字符串是否相等 != 比较两个字符串是否不相等 -n 判断字符长度是否大于零 -z 判断字符长度是否等于零 2.数字比较 如下的操作符可以用来比较两个数: -eq 比较两个数是否相等 - ge 比较一个数是否大于或是等于另一个数 -le 比较一个数是否大于或是等于另一个数 -ne 比较两个数是否不等 -gt 比较一个数是否大于另一个数 -lt 比较一个数是否小于另一个数
3.文件操作符 如下的操作符可以用来做文件比较操作符: -d 确定文件是否为目录 -f 确定文件是否为普通文件 -r 确定是否对文件设置了读许可。 -s 确定文件名是否具有大于零的长度 -w 确定文件是否设置了写许可 -x 确定文件是否设置了执行许可 4 .逻辑操作符 逻辑操作符是用来根据逻辑规则比较表达式。字符表示NOT 、AND和OR ! 求反(”非”)逻辑表达式 -a 逻辑AND(”与 ”)两个逻辑表达式 -o 逻辑OR(”或 ”)两个逻辑表达式
8.6.2 tcsh 1.字符串比较 如下的操作符可以用来比较两个字符串的表达式: 操作符 说明 = = 比较两个字符串是否相等 != 比较两个字符串是否不相等 2 .数字比较 如下的操作符可用来比较两个数: 操作符 说明 >= 比较一个数是否大于或等于另一个数 <= 比较一个数是否小于或等于另一个数 > 比较一个数是否大于另一个数 > 比较一个数是否小于另一个数
3文件操作符 如下的操作符可以用来做文件比较操作符: 操作符 说明 -d 确定文件是否为目录 -e 确定文件是否存在 -f 确定文件是否为普通文件 -r 确定是否对文件设置了读许可。 -o 确定用户是否为文件的拥有者 -w 确定文件是否设置了写许可 -x 确定文件是否设置了执行许可 -z 确定文件大小是否为零 4逻辑操作符 逻辑操作符与条件语句一起使用。下面的操作符用来执行逻辑非、AND和OR: 操作符 说明 ! 求反(”非”)逻辑表达式 -a 逻辑AND(”与 ”)两个逻辑表达式 -o 逻辑OR(”或 ”)两个逻辑表达式
8.7重复语句 8.7.1 for 语句 第一种格式如下: for curvar in list do statements done 对list中的每个值需要执行一次statements时应使用这种格式。对每次循环,把list中的当前值赋给变量vcurvar. List可以使含有几个项的变量,或是用空格分隔的值表。For语句的这种格式是由pdksh和bash使用的。
第二种格式如下: for curvar do statements done 在这种格式中,对传给shell_程序的每个位置参数执行一次statements。对每次循环,把位置参数的当前值赋给变量curvar。 在tcsh下,for语句叫做foreach. 其格式如下: foreach curvar(list) end 在这种方式中,对list中的每个值执行一次statements。
8.7.2 while语句 while语句用来当指定的条件为真时执行一系列的命令。一旦所制定的条件判断为假时,循环就立即终止。 在pdksh和bash 中,利用的如下的各式: while expression do statements done 在tcsh 中,利用如下的格式: while (expression) end
8.7.3 until语句 until语句可以用来执行一系列命令直到所指定的条件为真才能终止。 在pdksh和bash中,利用如下的格式: until expression do statements done 正如所见到的,这种格式类似于while语句。 tcsh 不支持until 语句。
8.7.4 repeat语句 repeat语句是用来执行只有一个固定的次数的命令。 如要在屏幕上显示连字符(-)100次,则利用如下的命令: repeat 100 echo ‘-’
8.7.5 select语句 当编写一个要从用户联机输入的shell程序时,shell语句就可用来生成一个菜单列表。Select语句的格式如下: select item in itemlist do statements done itemlist是可选的。当未给出itemlist时,系统通过item中的项目一次重复一个,但当给出itemlist时,系统对itemlist中的每个项重复,对每次重复把itemlist的当前值赋给item,而后item可作为执行语句的一部分。
8.7.6 shift 语句 shift语句是用来处理位置参数的,并从左到右每次处理一个参数。应该记得,位置参数是用$1、$2、$3等来标识的。shift 命令的作用时,把每个位置参数向左移动一个位置,而当前的$1丢失。 shift命令的格式如下: shift number 参数number是移动的数目,是可选的。当不特别指定number时,缺省值为1,即参数向左移动一个位置。当指定number时,则向左移动number个位置。
8.8 条件语句 8.8.1 if 语句 if语句通过判断逻辑表达式来作出选择,在pdksh和bash中的条件语句有如下的格式: if [ expression ]; then statements elif [ expression ]; then else fi if条件是可以嵌套的,If条件中的elif或else部分并不是必要的。如果在if语句和相继的elif语句中所指定的表达式可选的都不为真时,则可执行else部分。fi是用来指出if语句的结束,在嵌套if条件的情况下,fi是很有用的。在这种情况下应该让fi与if相匹配,以确保所有的if 语句是正确的编码。
在tcsh中,if语句有两种格式。 第一种格式类似于pdksh和bash的格式,如下所示: if (expression) then Statements else if (expression) then else Endif tcsh的第二种if条件的格式如下: if (expression) command 在这种格式中,当表达式的判定为真时,只能执行单命令。
8.8.2 case语句 case语句是用来执行依赖于离散值或是匹配指定变量值的范围的语句。在大多数情况下,如果存在大量的条件,就可以用case语句来替代if语句。 pdksh和bash的case语句如下: case str in str1 | str2) statements;; str3 | str4) *) esac 可以对每个条件指定若干个离散值(例如str1、str2等等),或是通配符指定值。最后的条件应是*(星号),当其他的条件都不满足时执行它。对所指定条件中的每个条件,执行全部关联的语句,直到双分号(;;)时终止。
8.9杂项语句 break 语句 break语句可以用来终止重复执行的循环。这种循环可以是for、until或repeat。 命令。 exit语句 exit语句可以用来退出shell程序。在exit之后可有选择的利用一个数字。如果当前的shell程序被另一个shell程序调用,那么这个调用程序检查代码,并做出相应的判断。
8.10 函数 如同其它的编程语言一样,shell程序也支持函数。函数是shell程序中执行特殊过程的部件,并在shell程序中可以重复调用。编写函数将有利于编写没有重码的shell程序。 下面是在pdksh和bash中函数定义格式。 func(){ Statements } 可以调用函数如下: func param1 param2 param3 参数param1 param2等是可以选择的。还能把参数作为单字符串来传送,例如$@.函数可以分析参数,就好像它们是传送给shell程序的位置参数。