第九章 SHELL编程
9.1 SHELL编程概述
在unix系统中,像在DOS中的batch一样,你可以把一系列命令输入到一个叫做script的文件中. 利用source命令或者设置这个文件的x(可运行)属性并直接键入该文件名, 就像用一个命令那样, 你就可以让 C shell 从文件中读入命令并执行它们.
当你执行一个shell script时, 系统会检查script文件的第一行以确定如何执行其中的命令: ○ 如果第一行以#!开始, 后面跟着一个程序名, 系统就会用那个程序来执行script中后面的命令. ○ 如果第一行以#开始, 系统会用Cshell执行script. 等同于#!/bin/csh ○ 如果第一行不是以#开始, 系统就会用Bshell来执行script. 等同于#!/bin/sh
9.2 C shell编程
1. SCRIPT中的参数及变量
如何将命令行的参数传给script呢? 可以这样: 键入script名, 后面跟任何你想要传递的参数。 Cshell把script名后面的字符按照词(words)来划分后传递给一个叫做argv的变量数组, 叫做arguments list。 这样命令行的参数就作为words存储于argv中, 连同script名, 分别可以被引用为argv[0], argv[1], 。。。 argv[n], 或者你也可以用等效的方法即$0,$1,…,$n来引用它们,其中n是参数的个数。这一点与C语言编程很类似。
除了argv, $0, $1, …, $n, 等以外, 你还可以在script中使用其他变量。 有许多符号可以对变量进行操作: 读取, 赋值, 判断属性等等。 分述如下: o$?name 判断变量是否存在, 若存在(被set过)则等于 1 。 否则等于 0 。 例如:
% set var='abc' % echo $?var #结果为 1 % unset var % echo $?var #结果为 0
o$#name 计算变量name中的词(words)数. 例如: % set var=(a b c) # $#var == 3 % set var='abc' # $#var == 1 % unset var # var: Undefined variable.
o$$ $$是Cshell的特殊变量, 用于表示执行此script时的进程号. 因为进程号是唯一的, 你可以用$$来生成一个唯一的临时文件,比如tmp.$$. 它可以避免任何文件名的冲突. 当然你也可以开发你自己对$$的独特应用.
o$< 重定向符号. 即从终端读入(一行). 比如: echo -n "yes or no?" set a=($<) 即变量a从终端输入. (如果你输入了一个空行或^D, $#a将等于 0 ) $n和$argv[n]实际上有个微小的差别: 当n大于参数个数($#argv)时, $argv[n]要报错,而$n永远也不会有这种"下标溢出"的错. 对其他变量, 也不会发生"下标溢出"的错误, 例如: 当(n > $#var) 时, $var[n-]不给任何结果和错误信息. 而$var[m-n]给出$var[m]到$var[$#var]的words.如果(m > $#var) 则没有任何结果.
2.文件操作格式
-操作符 filename -e 文件存在返回1(.true.), 否则返回0(.false.). -r 文件可读返回1,否则返回0. -w 文件可写返回1,否则返回0. -x 文件可执行返回1,否则返回0. -o 文件属于用户本人返回1, 否则返回0. -z 文件长度为0返回1, 否则返回0. -f 文件为普通(plain)文件返回1, 否则返回0. -d 文件为目录文件时返回1, 否则返回0.
3.路径名操作 你可以对路径名进行操作, 以便于去掉你不需要的部分. :t (tail)只保留路径名最右边的部分, 而将前面的全部去掉. (相当于basename) :r (root)去掉从"."(dot)开始的后缀部分. :e (end)去掉从左边开始一直的"."的前缀部分. :h (head)去掉最后的一部分, 只保留文件所在的目录名.
比如, 你有一个叫做 /usr/people/user1/file1.txt的文件, 在script中将它赋值给变量var_file, 则: $var_file:t == file1.txt $var_file:r == /usr/people/user1/file1 $var_file:e == txt $var_file:h == /usr/people/user1
4.返回代码 严谨的程序应该测试返回代码以判断该程序是正常结束还是别的情况.尤其在你写前后相关的script的时候, 后面的命令要用到前面命令的执行结果的时候.
一个命令执行后的返回代码存放在叫做status的变量中, 当命令执行成功正常退出时status为0, 否则为1. 比如你想检查前面一个命令是否正常地被执行了, 从而判断下一个命令是否应该执行,就可以:
command1
set checkpoint=$status
[commands...]
if(! $checkpoint) then
command2
else
command3
endif
5. 控制结构 Cshell中基本的控制结构包括 foreach, if结构, 另外还有switch及while,当然还有那个从程序设计概念提出来开始就一直存在的幽灵: goto.
1. 控制循环的foreach 语法为:
foreach variable (variable_value lists)
{commands}
end
变量variable依次取lists中的值, 执行command(s)命令. lists中给出多少个值, 就进行多少次操作. 结束循环后变量variable的取值为lists中的最后一项.
○ foreach-end中间可以用 break 以及 continue 控制循环的中断及继续: break终止循环, continue 终止一轮循环操作并开始下一轮循环. ○ noglob变量的设置可以防止lists中的值作文件名扩展. 在script的前面set即可. set noglob 比如你的lists是 (a b c*), set noglob的结果是直接解释成a, b, c*; 而没有设noglob时则解释成a, b, 以c开始的文件名. 如果你的目录下没有这样的文件时, 就会报错(No match). 当然你应该在script的结束时unset noglob, 以不影响后面的操作.
2. 条件控制 if ○ 语法为:
if ( expression ) then
[commands]
else
[commands]
endif
○ 另外还可以用else if:
if ( expression ) then
[commands]
else if ( expression ) then
[commands]
else
[commands]
endif
○ 还可以用简化格式: if ( expression ) command 或者 if ( expression ) \ command # "\"(backslash)后面只能接newline(回车即可), 不能有任何其他字符; # 单个命令command不能包括"|", "&" 以及";". 也不能使用其它控制语句.
○ 不能使用下面的格式: if ( expression ) then 或 if ( expression ) then command endif
3. 循环控制 while 语法为:
while ( expression )
[commands]
end
# while中也可以使用break以终止循环. 例程(本例执行10次循环):
#!/bin/csh
set ai=1
while ( $ai <= 10 )
echo the ${ai}th time running.
@ ai++
end
4. 开关控制 switch 语法为:
switch ( $word )
case str_1:
[commands]
breaksw
...
case str_n:
[commands]
breaksw
default:
[commands]
breaksw
endsw
# word为控制变量, breaksw 跳出 switch 操作.
5. goto 语法为: goto label 例如(此例为无限循环!):
loop:
[commands]
goto loop
6. 其它
1. 中断处理 如果你的script还没有运行结束, 又不想继续运行, 你可能要按下^C以终止执行它,又或者你的script设计成那种无限循环式的, 即允许使用者重复执行直到按下^C(比如查询程序). 按下^C后, 系统会终止整个script, 但是如果你不想这样做(比如你还想删除中间的某些临时文件), 就可以在script中设定中断处理: onintr label label是标识行, 其结果是你按了^C后, goto到label行继续执行.
2. exit 前面讲过命令有返回代码, 同样script也可以有返回代码. 用exit可以终止script的执行并返回一个值: exit ( status ) status 即是你要返回的值.
3. expression(表达式) if和while都要用到expression, expression可以是变量值以及他们的操作结果, 或者是任何返回数值的操作. 比如 ( $var ), ( -e filename )等等.C 中的所有代数及逻辑运算符都可以用于Cshell的expression中. 比如 == 和 !=比较两个字符是否相同, && 和 || 表示逻辑 "与" 和 "或", "!" 表示 "非".代数运算使用expr, 如 expr $a + $b。
| | |