UNIX SHELL编程.docx
《UNIX SHELL编程.docx》由会员分享,可在线阅读,更多相关《UNIX SHELL编程.docx(20页珍藏版)》请在冰豆网上搜索。
UNIXSHELL编程
ShellScript编程
□前言
在DOS中,你可能会从事一些例行的重覆性工作,此时你会将这些重覆性的命令写成批次档,只要执行这个批次档就等於执行这些命令。
大家会问在UNIX中是否有批次处理这个东东,答案是有的。
在UNIX中不只有如DOS的批次处理,它的功能比起DOS更强大,相对地也较复杂,已经和一般的高阶语言不相上下。
在UNIX中大家都不叫做批次档,而叫做ShellScript。
一般而言,ShellScript的地位和其它的可执行档(或命令)是完全相同的,只不
过ShellScript是以文字档的方式储存,而非二进位档。
而执行ShellScript时,必须
有一个程式将其内容转成一道道的命令执行,而这个程式其实就是Shell,这也就是为
什麽我们叫做ShellScript的原因(往後我们称为Script)。
不同Shell的Script基本
上会有一些差异,所以我们不能将写给Ashell的Script用Bshell执行。
而在UNIX中
大家最常使用BourneShell以及CShell,所以这堂课就介绍这两种Script的写法。
□将文字档设为可执行的ShellScript
如果我们已经写好Script,如何将其设成可执行档呢?
因为Script其实是一个可执行档,所以必须将其存取权设定成可执行。
我们可以使用下列命令更改存取权:
chmodu+xfilename只有自己可以执行,其它人不能执行
chmodug+xfilename只有自己以及同一群可以执行,其它人不能执行
chmod+xfilename所有人都可以执行
而我们如何指定使用那一个Shell来解释所写的Script呢?
几种基本的指定方式如
下所述:
1.如果Script的第一个非空白字元不是"#",则它会使用BourneShell。
2.如果Script的第一个非空白字元是"#"时,但不以"#!
"开头时,则它会使用CShell。
3.如果Script以"#!
"开头,则"#!
"後面所写的就是所使用的Shell,而且要将整个路径名称指出来。
这里建议使用第三种方式指定Shell,以确保所执行的就是所要的。
BourneShell的路
径名称为/bin/sh,而CShell则为/bin/csh。
1.使用BourneShell
┌——————————┐┌——————————┐
│echoenterfilename││#!
/bin/sh│
│.│or│.│
│.││.│
│.││.│
└——————————┘└——————————┘
2.使用CShell
┌——————————┐┌——————————┐
│#CShellScript││#!
/bin/csh│
│.││.│
│.││.│
│.││.│
└——————————┘└——————————┘
3.使用/etc/perl
┌——————————┐
│#!
/etc/perl│
│.│
│.│
│.│
└——————————┘
除了在Script内指定所使用的Shell外,你也可以在命令列中强制指定。
比如你要
用CShell执行某个Script,你可以下这个命令:
cshfilename
此时的Script的存取权就不一定要为可执行档,其内部所指定的Shell也会无效,详细
的情形後面会讨论。
□Script的基本结构及观念
Script是以行为单位,我们所写的Script会被分解成一行一行来执行。
而每一行可
以是命令、注解、或是流程控制指令等。
如果某一行尚未完成,可以在行末加上"\",
这个时候下一行的内容就会接到这一行的後面,成为同一行,如下
┌———————————┐
│echoThemessageis\│
│toolongsowehave\│
│tosplititinto\│
│severallines│
└———————————┘
当Script中出现"#"时,再它後面的同一行文字即为注解,Shell不会对其翻译。
在Script中要执行一个命令的方法和在命令列中一样,你可以前景或背景执行,执行命令时也会需要设定一些环境变数。
Script的流程控制和一般高阶语言的流程控制没有什麽两样,也和高阶语言一样有副程式。
这些使得Script的功能更加强大。
为了达到与高阶语言相同的效果,我们也可以在Script中设定变数,如此使Script成为一个名付其实的高阶语言。
□BourneShell
一、变数
BourneShell的变数型态只有字串变数,所以要使用数值运算则必须靠外部命令达成目的。
而其变数种类有下列几种:
1.使用者变数
这是最常使用的变数,我们可以任何不包含空白字元的字串来当做变数名称。
设定变数值时则用下列方式:
var=string
取用变数时则在变数名称前加上一"$"号。
┌———————┐
│name=Tom│
│echoname│
│echo$name│
└———————┘
结果如下:
name
Tom
2.系统变数(环境变数)
和使用者变数相似,只不过此种变数会将其值传给其所执行的命令。
要将一使用者变数设定为系统变数,只要加上:
exportvar
┌———————┐
│name=Tom│
│exportname│
└———————┘
以下是使用者一进入系统之後就已设定好的系统变数:
$HOME使用者自己的目录
$PATH执行命令时所搜寻的目录
$TZ时区
$MAILCHECK每隔多少秒检查是否有新的信件
$PS1在命令列时的提示号
$PS2当命令尚未打完时,Shell要求再输入时的提示号
$MANPATHman指令的搜寻路径
3.唯读的使用者变数
和使用者变数相似,只不过这些变数不能被改变。
要将使用者变数设成唯读的
,只要加上:
readonlyvar
而若只打readonly则会列出所有唯读的变数。
还有一点,系统变数不可以设定
成唯读的。
┌———————┐
│name=Tom│
│readonlyname│
│echo$name│
│name=John│
│readonly│
└———————┘
结果如下:
Tom
name:
isreadonly
readonlyname
readonly......
4.特殊变数
有些变数是一开始执行Script时就会设定,并且不以加以修改,但我们不叫它唯读的系统变数,而叫它特殊变数(有些书会叫它唯读的系统变数),因为这些变数是一执行程式时就有了,况且使用者无法将一般的系统变数设定成唯读的。
以下是一些等殊变数:
名称
意义
$0
这个程式的执行名字
$n
这个程式的第n个参数值,n=1..9
$*
这个程式的所有参数
$#
这个程式的参数个数
$$
这个程式的PID
$!
执行上一个背景指令的PID
$?
执行上一个指令的返回值
当你执行这个程式时的参数数目超过9个时,我们可以使用shift命令将参数往前移一格,如此即可使用第10个以後的参数。
除此之外,吾人可以用set命令改变$n及$*,方法如下:
setstring
如此$*的值即为string,而分解後则会放入$n。
如果set命令後面没有参数,
则会列出所有已经设定的变数以及其值。
档名:
ex1参数:
thisisatest
┌———————————┐
│echoFilename:
$0│
│echoArguments:
$*│
│echoNo.ofargs.:
$#│
│echo2ndarg.:
$2│
│shift│
│echoNo.ofargs.:
$#│
│echo2ndarg.:
$2│
│sethello,everyone│
│echoArguments:
$*│
│echo2ndarg.:
$2│
└———————————┘
结果如下:
Filename:
ex1
Arguments:
thisisatest
No.ofargs.:
4
2ndarg.:
is
No.ofargs.:
3
2ndarg.:
a
Arguments:
hello,everyone
2ndarg.:
everyone
值得一提的是,当你想从键盘输入一变数值时,你可以使用下面的命令:
readvar1var2.....
这时read会将一个字分给一个变数。
如果输入的字比变数还多,最後一个变数会将
剩下的字当成其值。
如果输入的字比变数还少,则後面的变数会设成空字串。
如果需要处理数值运算,我们可以使用expr命令。
其参数及输出列於附录A。
二、执行命令
在BourneShell中有五种方法执行一个命令,而这五种方式所产生的果有些许的不
同。
1.直接下命令
这个方式和在命令列中直接下命令的效果一样。
2.使用sh命令
shcommand
这个档案必须是BourneShell的Script,但这个档案并不一定要设成可执行。
除此之外和直接下命令的方式一样。
3.使用"."命令
.command
这时和使用sh命令相似,只不过它不像sh一般会产生新的process,相反地,
它会在原有的process下完成工作。
4.使用exec命令
execcommand
此时这个Script将会被所执行的命令所取代。
当这个命令执行完毕之後,这个
Script也会随之结束。
5.使用命令替换
这是一个相当有用的方法。
如果想要使某个命令的输出成为另一个命令的参数
时,就一定要使用这个方法。
我们将命令列於两个"`"号之间,而Shell会以
这个命令执行後的输出结果代替这个命令以及两个"`"符号。
str='Currentdirectoryis'`pwd`
echo$str
结果如下:
Currentdirectoryis/users/cc/mgtsai
这个意思是pwd这个命令输出"/users/cc/mgtsai",而後整个字串代替原
来的`pwd`设定str变数,所以str变数的内容则会有pwd命令的输出。
number=`expr$number+1`
这就是先前所提要作数值运算的方法,基本上expr命令只将运算式解,而
後输出到标准输出上。
如果要将某变数设定成其值,非得靠命令替换的方
式不可。
这个例子是将number变数的值加1後再存回number变数。
三、流程控制
在介绍流程控制之前,我们先来看看test命令。
test命令的参数是条件判断式,当
条件为真时则传回非零值,而条件为伪时则传回零。
在所有的流程控制都必须用到
test命令来判断真伪。
而test命令的使用方法则列於附录B。
test$#=0
如果执行这个程式没有参数时,会传回非零值代表"$#=0"这个条件成立。
反
之则会传回零。
以下介绍各种流程控制:
1.ifthen
语法以及流程图如下
语法以及流程图如下
│FALSE
if(condition)<condition>—┐
then│TRUE│then-commandsthen-commands│
fi├————┘
│
condition是一个test命令。
往後所介绍的各种流程中的condition都是test
命令。
档名:
chkarg
┌———————————┐
│if(test$#!
=0)│
│then│
│echoArg1:
$1│
│fi│
└———————————┘
$chkargHello
Arg1:
Hello
$chkarg
$
2.ifthenelse
语法以及流程图如下
│FALSE
if(condition)<condition>—————┐
then│TRUE│
then-commandsthen-commandselse-commands
else├————————┘
else-commands│
fi
3.ifthenelif
语法以及流程图如下
│FALSE
if(condition1)<condition1>—┐
then│TRUE│FALSE
commands1commands1<condition2>—┐
elif(condition2)││TRUE│
then│commands2commands3
commands2├—————┴————┘
else│
commands3
commands3
fi
echo'word1:
\c'
readword1
echo'word2:
\c'
readword2
echo'word3:
\c'
readword3
if(test"$word1"="$word2"-a"$word2"="$word3")
then
echo'Match:
words1,2,&3'
elif(test"$word1"="$word2")
then
echo'Match:
words1&2'
elif(test"$word1"="$word3")
then
echo'Match:
words1&3'
elif(test"$word2"="$word3")
then
echo'Match:
words2&3'
else
echo'Nomatch'
fi
4.forin
语法以及流程图如下
│FALSE
forvarinarg-list┌—<arg-list还有东西吗?
>—┐
do││TRUE│
commands│从arg-list取得一项│
done│放到变数var│
│││
│commands│
└——————┘│
┌———————————┐┌———————┘
│forainxxyyzz││
│do│
│echo$a│
│done│
└———————————┘
结果如下:
xx
yy
zz
5.for
语法以及流程图如下
│FALSE
forvar┌—<参数中还有东西吗?
>—┐
do││TRUE│
commands│从参数中取得一项│
done│放到变数var│
│││
│commands│
└—————┘│
档名:
lstarg┌———————┘
┌———————————┐│
│fora│
│do│
│echo$a│
│done│
└———————————┘
$lstargxxyyzz
xx
yy
yy
zz
6.while
语法以及流程图如下
│FALSE
while(condition)┌—<condition>—┐
do││TRUE│
commands│commands│
done└————┘│
┌————┘
│
┌———————————————┐
│number=0│
│while(test$number-lt10)│
│do│
│echo"$number\c"│
│number=`expr$number+1`│
│done│
│echo│
└———————————————┘
结果如下:
0123456789
7.until
语法以及流程图如下
│TRUE
until(condition)┌—<condition>—┐
do││FALSE│
commands│commands│
done└————┘│
┌————┘
│
它和while的不同只在於while是在条件为真时执行回圈,而until是在条件
为假时执行回圈。
8.break及continue
这两者是用於for,while,until等回圈控制下。
break会跳至done後方执行
,而continue会跳至done执行,继续执行回圈。
9.case
语法以及流程图如下
│TRUE
casestrin<str=pat1>————commands1—┐
pat1)commands1;;│FALSETRUE│
pat2)commands2;;<str=pat2>————commands2—┤
pat3)commands3;;│FALSETRUE│
esac<str=pat3>————commands3—┤
│FALSE│
├————————————┘
│
而pat除了可以指定一些确定的字串,也可以指定字串的集合,如下
*任意字串
?
任意字元
[abc]a,b,或c三字元其中之一
[a-n]从a到n的任一字元
|多重选择
┌———————————————┐
│echo'EnterA,B,orC:
\c'│
│readletter│
│case$letterin│
│A|a)echo'YouenteredA.';;│
│B|b)echo'YouenteredB.';;│
│C|c)echo'YouenteredC.';;│
│*)echo'NotA,B,orC';;│
│esac│
└———————————————┘
10.函数
格式如下
function-name()
{
commands
}
而要呼叫此函数,就像在命令列下直接下命令一般。
□CShell
CShell有些特性和BourneShell一样,但有些不相同。
这里介绍与BourneShell
不相同的地方。
一、变数
1.字串变数
这个部分和BourneShell的变数一样,只不过在设定变数值时不能使用Bourne
Shell的方式,而必须打:
setvar=value
2.数字运算
基本上CShell没有数字变数,但CShell却有简单的方法处理数字运算:
@varoperatorexpression
operator可以是C语言中的=,+=,-=,......,而expression则是运算式。
运
算式的运算子如下:
A.()改变计算的顺序
~@
B.~位元NOT运算
@~
!
逻辑否定
C.%取馀数
/除*乘-减+加
D.>>右移
<<左移
E.>大於
<小於>=大於等於
<=小於等於!
=不等於
==等於
F.&位元AND运算
^位元XOR运算|位元OR运算
G.&&逻辑AND
||逻辑OR
除此之外,我们也可以检验一个档案的状态,如下
-nfilename
而-n可为下列之一
-d档案是一个目录档案
-e档案存在
-f档案为一般的档案
-o使用者拥有这个档案
-r使用者可以读取这个档案
-w使用者可以写入这个档案
-x使用者可以执行这个档案
-z档案长度为0
@count=count+1
@flag=-e/users/cc/mgtsai/mail&&-e/usr/spool/mail
3.阵列
在CShell中,我们可以宣告阵列变数,方式如下
setvar=(val1val2......)
而var[1]之值为val1,var[2]之值为val2......。
而$var代表整个阵列。
我们
可以用$#var来计算阵列个数,也可以用$?
var来检查某个变数是否已宣告。
4.特殊变数
$argv和BourneShell的$*相似,只不过这是一个阵列。
$argv[n]和BourneShell的$n相同,但不受个数限制。
$#argv和BourneShell的$#相同
$home和BourneShell的$HOME相同
$path和BourneShell的$PATH相似,只不过这是一个阵列
$prompt和BourneShell的$PS1相同
$shellShell的路径名称
$status和BourneShell的$?
相同
$$和BourneShell的$$相同
$<键盘输入
二、执行命令
基本上和BourneShell相同,只有一点在BourneShell中的"."命令在CShell中
则为"source"命令。
三、流程控制
在CShell中流程控制不像BourneShell中一般需要使用test命令。
相反地,它和
C语言类似只要在条件中写出运□式即可。
当运算结果不为零时,其值为真,为零
时其值为伪。
以下是CShell的流程控制
1.if
语法如下
if(expression)simple-command
2.goto
语法如下
gotolabel
这时程式会跳至以l"label:
"开头的那一行执行
if($#argv==2)gotogoodargs
echo'Pleaseusetwoarguments.'
exit
goodrags:
...
3.