Linux Shell编程(基础教程)

上一篇 / 下一篇  2008-11-30 22:25:17 / 个人分类:Shell 编程

  • 文件版本: V1.0
  • 开发商: 本站原创
  • 文件来源: 本地
  • 界面语言: 简体中文
  • 授权方式: 免费
  • 运行平台: Win9X/Win2000/WinXP

%]3K5HK-S8TN}mW| k01. Linux 脚本编写基础
;E!\~"uT N'OB&e01.1 语法基本介绍51Testing软件测试网"pboyOS
1.1.1 开头
p0z|*Y0RI3bO0       程序必须以下面的行开始(必须放在文件的第一行):
el&l'[A o0       #!/bin/sh
;^`8O!K+BxF0    符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。  当编辑好脚本时,如果要执行该脚本,还必须使其可执行。
pwo7cFM0    要使脚本可执行:   编译 chmod +x filename 这样才能用./filename 来运行51Testing软件测试网2a-YK/y-G,O,F
1.1.2 注释
q,_(m:X!S0  在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。51Testing软件测试网1j:K|J2`p:e(@3k*u^
1.1.3 变量51Testing软件测试网&v7r3sn^U\"I
  在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写:
9| H9b}5L0        #!/bin/sh
@4a;nmR0        #对变量赋值:
$Wg9_u:N m!S0        a="hello world"
O'|hi Wk}0        # 现在打印变量a的内容:51Testing软件测试网2CZ,x eg8O
        echo "A is:"51Testing软件测试网%R NF%pt
        echo $a
+{1p ^E5C]V0       有时候变量名很容易与其他文字混淆,比如:
Lzt~/T$}-n3f3@0        num=251Testing软件测试网c+Zd"cLIG;X
        echo "this is the $numnd"
0rVL5[)i#}O]Hu/y0       这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:
cO-k+P,r`)b9e0        num=251Testing软件测试网-@5ee6G$WU
        echo "this is the ${num}nd"
(s1XWnQxXN&a2W0        这将打印: this is the 2nd51Testing软件测试网+|g0B.Q.}
1.1.4 环境变量
-q)\|t"h|y*l0       由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录51Testing软件测试网,F |5[*Y7{
脚本中使用环境变量。51Testing软件测试网 \ rD7K A3R"E'@g
1.1.5 Shell命令和流程控制
5MH%Ny&u1Tc,Rh*K0       在shell脚本中可以使用三类命令:
"E_7ZAs/||0       1)Unix 命令:
3_6p8O&GDY3F{ I)_0      虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来进行文件和文字操作的。
4qv%j9p4E5z0        常用命令语法及功能51Testing软件测试网U{ `/DG7Z[~nR
  echo "some text": 将文字内容打印在屏幕上51Testing软件测试网O/MV!gH_L
  ls: 文件列表
4e AO-q0L/_Sq,u-S0  wc –l filewc -w filewc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数51Testing软件测试网4n G RV V ~0~o*Y
  cp sourcefile destfile: 文件拷贝
#G r8Te4uq)EKY6xH0  mv oldname newname : 重命名文件或移动文件
E+J\Ne@0  rm file: 删除文件
q;?,m[#_*W rf0  grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt51Testing软件测试网3O"_.R-Lz.bJk
  cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,这是两个完全不同的命令51Testing软件测试网*fS-w,U'P1~7i
  cat file.txt: 输出文件内容到标准输出设备(屏幕)上51Testing软件测试网d$r] v4TeZ
  file somefile: 得到文件类型
l}5O#z I[/iGc0  read var: 提示用户输入,并将输入赋值给变量
kss[)Xq(a-p0  sort file.txt: 对file.txt文件中的行进行排序51Testing软件测试网0@ZVj W#r"x
  uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq
-ke cDC!HsZ0  expr: 进行数学运算Example: add 2 and 3expr 2 "+" 351Testing软件测试网CW[:g^@*}u:o
  find: 搜索文件比如:根据文件名搜索find . -name filename -print
8T0D4N1W9sK%k@%x]0  tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile51Testing软件测试网 Hn+~gL(b
  basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux
C!@1l_ P-fYr,h#M0  dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin51Testing软件测试网5H!x4YbCgAy"d
  head file: 打印文本文件开头几行51Testing软件测试网gaB*L5t!R
  tail file : 打印文本文件末尾几行51Testing软件测试网^m3q ~A e
  sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。不要和shell中的通配符相混淆。比如:将linuxfocus 替换为LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
5qh$n(_1MX7FG#q0  awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。
9k9HZ3i wG|0cat file.txt | awk -F, '{print $1 "," $3 }'这里我们使用,作为字段分割符,同时打印第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA
)Aa2I~(e|yT+[j0        命令输出结果为:Adam Bor, IndiaKerry Miller, USA51Testing软件测试网Q9aG9\6\ q5L&E
        2) 概念: 管道, 重定向和 backtick51Testing软件测试网'Euy)R r
  这些不是系统命令,但是他们真的很重要。
NMf"[6Tp0L Q0  管道 (|) 将一个命令的输出作为另外一个命令的输入。51Testing软件测试网8{0R Y0V E9bD
                 grep "hello" file.txt | wc -l51Testing软件测试网@D![\+^B/y
  在file.txt中搜索包含有”hello”的行并计算其行数。51Testing软件测试网(Cno,Q vJO
  在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。
M X+hO3\*gPY!u0  重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。51Testing软件测试网'F8T L7a@q~ _
      > 写入文件并覆盖旧文件51Testing软件测试网;zba4}S:spT
      >> 加到文件的尾部,保留旧文件内容。
Pr'n Xpb8Q0        反短斜线
-K/V2JBG N Hle0     使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。
os\ WiGXa5^0         命令:
0e uv\R1vp&f!C0           find . -mtime -1 -type f -print
/};s5L~,T,bg"Z+I0     用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您想将所有查找到的文件打一个包,则可以使用以下脚本:51Testing软件测试网 J g Z'}(v%^]C
             #!/bin/sh
:r Gj[6@ Y8@4J7d0             # The ticks are backticks (`) not normal quotes ('):
*f4I ^_`+|8U0              tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
ol-Z KD T[Qy0       3) 流程控制51Testing软件测试网$g.i]8AJ4k
        1.if
1KGnWX6DPoD4J0    "if" 表达式 如果条件为真则执行then后面的部分:
/j~'Gq:f0JB0            if ....; then51Testing软件测试网|.L C `bW["V8M
           ....
6^V U]5t-zp0           elif ....; then
1D~ M Gp_k.g{0           ....51Testing软件测试网-S6}Z})HIW
           else
n]:a%ti5s0           ....51Testing软件测试网v3]0^,ZU(D8l
           fi
$H4|AQ'i^,g(w)s0           大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等…
2S? RS EU}0    通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。
xwl4@.@9C5w] o0                 [ -f "somefile" ] :判断是否是一个文件
~9Ve7nwJ R0                 [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
F(Gf[7C)l C#^$W9["i0                 [ -n "$var" ] :判断$var变量是否有值51Testing软件测试网k _QV8cb
                 [ "$a" = "$b" ] :判断$a和$b是否相等51Testing软件测试网9i:]}^ o2dG,S
    执行man test可以查看所有测试表达式可以比较和判断的类型。
u9af:lL-D[0   直接执行以下脚本:51Testing软件测试网%](aAj0HSU-{
               #!/bin/sh
"GPJ"\1G B!{+J0S0               if [ "$SHELL" = "/bin/bash" ]; then51Testing软件测试网v.^+^ N*q4NiJ[\
                    echo "your login shell is the bash (bourne again shell)"51Testing软件测试网9Q/N(Y],R!t
               else
_9E}x5|D0                    echo "your login shell is not bash but $SHELL"
F6x+p!sLnO4fz0               fi
~A*GOV'? \0   变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。
7zgn8~"OR_M0P0       51Testing软件测试网$S/f*|OW/JM
        快捷操作符
oT3c'Z mP0        熟悉C语言的朋友可能会很喜欢下面的表达式:51Testing软件测试网 I3\PO:K3a8k{
                  [ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"
w5u$I {"_)f9V{NY+q0  这里 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在则打印” This computer uses shadow passwors”。同样或操作(||)在shell编程中也是可用的。这里有个例子:51Testing软件测试网'@7zvIiduu
                 #!/bin/sh
8_zP u"[_@%O0                 mailfolder=/var/spool/mail/james
R,K4I(U5ij;H0                 [ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" ; exit 1; }51Testing软件测试网2R+l^_ d&{%{BD
                 echo "$mailfolder has mail from:"51Testing软件测试网?|(HS9PF gI
                 grep "^From " $mailfolder51Testing软件测试网pC}}i O
        该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令:
*ZyA v'M-H0  -打印错误信息51Testing软件测试网0ip:j$c{/H5P
  -退出程序
L5K#b f#|!|8Ua6E0  我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。
Z u#B\%c,tv3r @y0  不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。51Testing软件测试网h:` mMTZ

51Testing软件测试网0[BA rWa#s h

         2.case
8?{qf[q0               case :表达式可以用来匹配一个给定的字符串,而不是数字。51Testing软件测试网:L ~8H{$vu/}.s5\
                      case ... in51Testing软件测试网(i5WS!H)K]9X J
                            ...) do something here ;;
|h;R%xE0                      esac
-T`2z?K(S+i&@y0         让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:51Testing软件测试网Nyh ^ d(d+l V
                     file lf.gz
)J#mD&S&bgq-G)f:i0                   这将返回:51Testing软件测试网*C4d/y:g#EV-h3C
                         lf.gz: gzip compressed data, deflated, original filename,51Testing软件测试网bH*j:[v+t D
                         last modified: Mon Aug 27 23:09:18 2001, os: Unix
C|&Ty.dGx mW0             我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件:51Testing软件测试网]9j]ut
               #!/bin/sh51Testing软件测试网6|2~"Q$u dVC
               ftype=`file "$1"`
z2Cs"U^XI0               case "$ftype" in
'b'@!V0a-zER3v0                       "$1: Zip archive"*)51Testing软件测试网 o;J"Z FR/@Hho
                  unzip "$1" ;;51Testing软件测试网fGT+LFT/M7wC
                         "$1: gzip compressed"*)
p^)K0|9@!fv@~0                    gunzip "$1" ;;
o~)V"eQH0                          "$1: bzip2 compressed"*)51Testing软件测试网1Aj7q DpG%R:T CM&C
                     bunzip2 "$1" ;;
;i ihm/y.HOQL0                           *) echo "File $1 can not be uncompressed with smartzip";;
0N-Ir%wv1H0                esac51Testing软件测试网]$M4h y!MC%qj
         您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。
s7r@9B]sp0也就是说,当我们运行:51Testing软件测试网 \]S(aA
                    smartzip articles.zip
@!` A*YxT0                    $1 就是字符串 articles.zip
Z-] Zo C R_ x0                3. selsect51Testing软件测试网P A2Q F2wx.\
                  select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。
0k8RA}"Y3R0                    select var in ... ; do
OB)S8zO*Lf_0                         break
]4w0i8m` t0                            done
/} l6{3A`rc0                            .... now $ var can be used ....
7c5d7{/T0k+|0                   下面是一个例子:
3j7u)s%T/V&J1a0                         #!/bin/sh
)]UDy6A l od0                         echo "What is your favourite OS?"51Testing软件测试网 NW2~#t,Z:O[ T%j
                         select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do51Testing软件测试网!T.`8u#h&B-hk6C{:\
                    break51Testing软件测试网Ti-U't&x I+U&Vu
                                done51Testing软件测试网i*[:d%Cs+pO X!L
                           echo "You have selected $var"
P`-a3F \n;t0              下面是该脚本运行的结果:51Testing软件测试网c)z,I0D5l+b*}j
                               What is your favourite OS?51Testing软件测试网;@;g nz*I/g k
                                    1) Linux
5{+`vT @k;F'{1t0                                    2) Gnu Hurd51Testing软件测试网;~Y8BwbK a
                                    3) Free BSD
)K*t+G8G8M#kTE.O0                                    4) Other51Testing软件测试网/t)t2p;iI!L0a:x y
                                  #? 151Testing软件测试网.k5b5p3]"d+n3w*R6j;^ J
                                You have selected Linux
7AM2x!R2_M9Z F0         注:var是个变量,可以换成其它的值。break用来跳出循环,如果没有break则一直循环下去。done与select对应。
Y)H {w:|)H3d0                  4.loop
?k)yA3VO9Cw0                      loop表达式:
_:["Tg5|-P(hQ?@0                            while ...; do
(Z Q2w/t j D}Y0                                      ....51Testing软件测试网`vc9S r [3B%y
                               done51Testing软件测试网;?$@9Ez.[Cy.f
             while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true.51Testing软件测试网(Xr{7iL0n:k\?
关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。
v;Z-y'[TE0  
4A!Q|+R-l Z(E0                     for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量:51Testing软件测试网S/f Kxk#`SG L$t
                          1,   for var in ....; do51Testing软件测试网GmOo(d9U(I(y
                                 ....51Testing软件测试网NCW?7C N,MO1K
                                done51Testing软件测试网:Mw qu#L!g Vmy
                       在下面的例子中,将分别打印ABC到屏幕上:
2Hp:ycnd&Drd&o$\0                            #!/bin/sh
4t;^l@ q*O0                                    for var in A B C ; do
["IcM-l3G0                                 echo "var is $var"
QM ]P ~8o"Xd$P0                                     done

5X/@c*C%Ceb051Testing软件测试网y&v v }%{JW

                           2,   for (( 条件一; 条件二; 条件三 );do51Testing软件测试网NS&[a-p
                                ...
F*S!Cda&FUnH;s'v5N~0                                done51Testing软件测试网@MK0DE n+n&p[9r
                        例:
6tP(?k^;s6w ]LG0                     51Testing软件测试网vv6`9lO"HF'L
                   for ((i=1;i<10;i=$[$i+1]));do51Testing软件测试网8{z4H)u0]

S4l/YD9l`9T` F0                             echo "a"
v C j,V#s+W?0                          done51Testing软件测试网@un+~FHQ
输出:51Testing软件测试网Qc0n~X%Wr!p

/a}8e VH0a51Testing软件测试网:YY ab t ? b+A;a R
a51Testing软件测试网&zgjNk]([
a
v2QBzA%c2H5V~|:L0a
m+x_"X+B0a51Testing软件测试网2@l5ghu"~4v H
a51Testing软件测试网oMo {8@WUF1W1s
a51Testing软件测试网:R'N9s Z8U+_A
a
7F [6F3E\0a51Testing软件测试网I{ gQa9DH

51Testing软件测试网E0xv8D*AS(z

条件一:这可以看成是『初始值』,如上面的例子中,初始值是 i=1 啦!
m4~if2F3O7R)r V0条件二:这可以看成是『符合值』,如上面的例子中,当 i<=100 的时候都是符合条件的!51Testing软件测试网I*} W*yy
条件三:这可以看成是『步阶』!也就是说, i 每次都加一! 所以啦!上面的例子是说:由 i=1 开始到 i<= 100 ,每次 i 都加一来执行底下的程序段(就是 s=s+i ),当 i >100 (也就是 i=101 )就跳出这一段程序段!怎样!不难吧!

Tx4j)ap"^9m051Testing软件测试网|&e5h:J"[2E2Y

 51Testing软件测试网#]x5lat

7xAv.wH,Z }0
B!D/v.U1?eF0                        下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:
2J C8s0sz$]D0                          #!/bin/sh
}$pa2Un`0                          # list a content summary of a number of RPM packages
|s|l.h0                          # USAGE: showrpm rpmfile1 rpmfile2 ...51Testing软件测试网-z9AW}I z;F
                          # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm51Testing软件测试网 ^k+y"['v&d M e m
                            for rpmpackage in $*; do51Testing软件测试网d-eZ(u!QN G:f
                         if [ -r "$rpmpackage" ];then51Testing软件测试网e3Sa RYX+u)d+p |
                         echo "=============== $rpmpackage =============="51Testing软件测试网 Y%q.sW eY$p7a4y+T
                          rpm -qi -p $rpmpackage51Testing软件测试网Q~a:EK7yJ.~-R$H
                          else51Testing软件测试网 F R?f/y*@G2kR
                           echo "ERROR: cannot read file $rpmpackage"
e*t0Lu0V5V0                         fi
:eu WGKRa0                              done
6Jz-y)I9T b!oj S?0                   这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。51Testing软件测试网&Dki;R6L7e
                        如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm51Testing软件测试网&I_l'``.x{1xKB#[
                                   此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.51Testing软件测试网Nm1h:OI4D4j

R/ul8r&Q0 

$Hq T/rj0?051Testing软件测试网g/b2QW8N$By4S

『until:直到条件相同的时候才离开程序』;
5^%wV1P*FA&Q0『while:当条件相同的时候,就继续做!』 

UQGg+G` GIo&d7J051Testing软件测试网 ~H%KE"GV*Q

until [ condition1 ] && { || } [ condition2 ] ...51Testing软件测试网4u%Q t)z Kw){

51Testing软件测试网~j9O2I XY

 51Testing软件测试网n)`r'I'n Z H-YX

51Testing软件测试网(h^atV


8zz7pN)xm0                 5. 引号51Testing软件测试网0}g+[?ts|
                   在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符(比如*)替换成合适的文件名,它变量替换成变量值。为了防 止程序作这种替换,您可以使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件, mail.jpg 和tux.jpg。
`*]"WQ*x1P4E0          编译SHELL脚本51Testing软件测试网YA.`F#nDPL
          #ch#!/bin/sh mod +x filename
1xem S(hlt0 cho *.jpg       ./filename 来执行您的脚本。51Testing软件测试网 W!d&FY&_S
  这将打印出"mail.jpg tux.jpg"的结果。51Testing软件测试网I{iu&R3@@#_
    引号 (单引号和双引号) 将防止这种通配符扩展:51Testing软件测试网Ogh1P2^
             #!/bin/sh51Testing软件测试网'oPf2pQ!~
             echo "*.jpg"51Testing软件测试网_Qn ? u?P
             echo '*.jpg'
&rN1Z@~6M~7N*L/j-[&M6c0  这将打印"*.jpg" 两次。51Testing软件测试网f|T.tk/~)|9c4v
  单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。
v,e9{@D^ K0         #!/bin/sh
+@O*i.LBP:t F~[0         echo $SHELL51Testing软件测试网v9oVxv8l
         echo "$SHELL"
E;h Lf9Zjm0         echo '$SHELL'
+l3iC9HF0   运行结果为:
!JP7RJV}0b,@/_0             /bin/bash
b [nW Ds8k#gv0             /bin/bash51Testing软件测试网$V2QIpDK4W/u.@5C;jV d
             $SHELL51Testing软件测试网&r w5\i D!X*g tJf
  最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:
oR0]%{ MO;l0           echo *.jpg
y~ I b x0           echo $SHELL51Testing软件测试网)t)K7yf%x(M"X
  这将输出:51Testing软件测试网@-Q4_R.U$sp4a
           *.jpg
)Z$S(t*R6?9Vl9H j0           $SHELL51Testing软件测试网4d#S HPU]
         6. Here documents
*fQ'li tX x `V0          当要将几行文字传递给一个命令时,here documents(译者注:目前还没有见到过对该词适合的翻译)一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents就不必用echo函数一行行输出。 一个 "Here document" 以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:
"e:M\)suk/~W0         #!/bin/sh51Testing软件测试网 M_mD;f
         # we have less than 3 arguments. Print the help text:51Testing软件测试网}5`'IC0R$Yn!Ib"N
            if [ $# -lt 3 ] ; then
~}W$QrQYG,mAs0                 cat <
+XP){dG{^0gB L.[0                 ren -- renames a number of files using sed regular expressions
&D*T `Q ]3^zm0                 USAGE: ren 'regexp' 'replacement' files...51Testing软件测试网)ut d4_b~+C
                 EXAMPLE: rename all *.HTM files in *.html:51Testing软件测试网0p6qp;W'k-q8L4}
              ren 'HTM$' 'html' *.HTM
T/b:zV|"w0                 HELP51Testing软件测试网}9M5G6fZt z
              exit 051Testing软件测试网 WO~3Mc.V h
            fi51Testing软件测试网#|%Ju3v3H;i$z j n9D
            ōLD="$1"
+t*U8I?:Yk+Za0            NEW="$2"
:m-I8D!zz @8K`x0Uy0          # The shift command removes one argument from the list of
crA\+cVc$~0          # command line arguments.51Testing软件测试网'wl,gY0I3u/S
          shift51Testing软件测试网9T1~*c6T?-C Sb
          shift
0V1C T&Uk4F:W#?:y3d1j/K,J0          # $* contains now all the files:51Testing软件测试网b:Dp/N2@0JN
         for file in $*; do
$DT(J*H0zg8Znj0          if [ -f "$file" ] ; then
%pBo0X1?*?0             newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`51Testing软件测试网D q7M&u5I%W!ri;_
             if [ -f "$newfile" ]; then51Testing软件测试网mo@(AvZ4yo-R
                  echo "ERROR: $newfile exists already"
mN?r4Qf\0             else
k(mQ ^tv0                  echo "renaming $file to $newfile ..."
Ly(p!r2X"R.q0                  mv "$file" "$newfile"
"q'OQ;G$j%f0l"R)|alqp P0              fi51Testing软件测试网&Ng q A`2\
            fi
*d^0Zj:Y2^a0           done
~ } d+r/hM F'N?j0        这是一个复杂一些的例子。让我们详细讨论一下。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。 如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从 参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我 们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目 的:得到了旧文件名和新
,yu.O)@ _/D'x Q-dk0文件名。然后使用mv命令进行重命名。
)r8v]r/UB'p0          4)函数51Testing软件测试网I$H5oC?)B
             如果您写了一些稍微复杂一些的程序,您就会发现在程序中可能在几个地方使用了相同的代码,并且您也会发现,如果我们使用了函数,会方便很多。一个函数是这个样子的:
sK'{*];gi0          functionname()51Testing软件测试网Lzo6Rm$T H"U/G&|+g
          {
yhE EwP1R@y0                 # inside the body $1 is the first argument given to the function
6s} CTLri2J @0                 # $2 the second ...
:N { DP~k#_N0                             body
c)s5V8^ T;v7P{&uq0            }51Testing软件测试网 S|6ORP)a&k
          您需要在每个程序的开始对函数进行声明。
^_n&`qe^5@!^B0   下面是一个叫做xtitlebar的脚本,使用这个脚本您可以改变终端窗口的名称。
9~(D q$wA pa0           这里使用了一个叫做help的函数。正如您可以看到的那样,这个定义的函数被使用了两次。
D#J8o#@:_J0               #!/bin/sh
}B\O I,_4F C0               # vim: set sw=4 ts=4 et:51Testing软件测试网 V1|7D aU2ee-I L
               help()51Testing软件测试网:v*gY~O2mg:zo
               {
9E#@4u"?H vh4B0              cat <
t5dK-sQ3U)y0                     xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole51Testing软件测试网?_(e9H)am n
                     USAGE: xtitlebar [-h] "string_for_titelbar"51Testing软件测试网6a[fl A[{u}
                      OPTIONS: -h help text
9VuT4Q"} N0                     EXAMPLE: xtitlebar "cvs"
7bDWEb'x0                     HELP
N I{'Bh2e~)j8R'{0             exit 0
V+IW@s oRO+k0               }
UO)K/T]0               # in case of error or if -h is given we call the function help:51Testing软件测试网 i5a1nw!b A^_2A H-j2n+L
               [ -z "$1" ] && help51Testing软件测试网Dk$g6vg1J,A d*fSF
               [ "$1" = "-h" ] && help
3r m\-IEF7A0               # send the escape sequence to change the xterm titelbar:
f/`C9CHw$t xZ0                 echo -e "33]0;$107"
Tu&lj%nX|F.V'\0                #
rO6t4t/Ek0            在脚本中提供帮助是一种很好的编程习惯,这样方便其他用户(和您)使用和理解脚本。51Testing软件测试网 sQr.U#q\/oUGkc
        命令行参数51Testing软件测试网 WM.dGBs
  我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。 但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (比如文件名)。有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无遗是一个不错的方法。51Testing软件测试网 Z{"nCy!v*gdK5@j
         #!/bin/sh51Testing软件测试网5K6@!s1\]S
         help()51Testing软件测试网;y \5d+B%q8\?\
         {51Testing软件测试网t(~/zn;DOv:I
            cat <51Testing软件测试网llk5dMd
               This is a generic command line parser demo.51Testing软件测试网8rS6{%Z H`b
               USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile251Testing软件测试网 D5B.Q0]ZCw%U
               HELP
"r%EP P9Ds%rNa0            exit 051Testing软件测试网tE@3@W%X:}"{
         }
O"OqM2I6~/@ `0          while [ -n "$1" ]; do
{+x5WQgV0        case $1 in
%pxh&t"gR0       -h) help;shift 1;; # function help is called
R#`0^!K d)dt0       -f) opt_f=1;shift 1;; # variable opt_f is set51Testing软件测试网b.B1mZ9X&o!t{
        -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
'F^7C9~g8w0Xw0        --) shift;break;; # end of options
Dk8f O*UnS0       -*) echo "error: no such option $1. -h for help";exit 1;;51Testing软件测试网x ||*v:K.EE*k8Eu
       *) break;;
v!Ll AB4j*| vv0          esac
_ vv*wNw X0          done51Testing软件测试网U+S7~ D:V-V]$`
          echo "opt_f is $opt_f"51Testing软件测试网vNdpF#aD
          echo "opt_l is $opt_l"51Testing软件测试网&fv%I f S5QB {&i
          echo "first arg is $1"
9zvO:h4rKQz'Vg*R0          echo "2nd arg is $2"
V)g-z:zA8h0  您可以这样运行该脚本:
3X'Z%qFz$Y)H0                 cmdparser -l hello -f -- -somefile1 somefile2
l4l*[.@"l)plF,fV0  返回的结果是:51Testing软件测试网9KEO a2Z\e;E
             opt_f is 151Testing软件测试网 [4wr4l4n H x|9B ke
             opt_l is hello
'P3\I`4v+c1uC0             first arg is -somefile1
0q$Q1E vis0             2nd arg is somefile2
)d2]&v]| X:VsH0  这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数.

'L,`!F)q*j l*?ll0

k(?,KD\wf-?T0
'DVz;D:K'kOx0UMp0第2部分 实例51Testing软件测试网%jeG9axJ

J'N)h X"H#l0    现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下copy命令:
0j]} P-N4T['h\ l0cp framework.sh myscrīpt51Testing软件测试网KT0|6k9y(E
 然后再插入自己的函数。51Testing软件测试网8B@|m| ^n&{
  让我们再看两个例子:51Testing软件测试网LcE2u7h E8n f a
  二进制到十进制的转换51Testing软件测试网E [ hFe
  脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:51Testing软件测试网h3[&x(V O:\FKB,f#X.{
#!/bin/sh51Testing软件测试网,[;U-U h%M bZD
# vim: set sw=4 ts=4 et:51Testing软件测试网'S$@{%u$O!v
help()
x^W7^#\/F k0{51Testing软件测试网E ffcET
 cat <51Testing软件测试网Rxb)fEr
b2h -- convert binary to decimal
vW%[~a$Y0USAGE: b2h [-h] binarynum
pghb/o ?0OPTIONS: -h help text51Testing软件测试网cw"~F b/_1B
EXAMPLE: b2h 11101051Testing软件测试网2akg }-V:b
will return 58
'u'ZQrcm"^0HELP51Testing软件测试网`.f;t V9P$Qd Q
 exit 051Testing软件测试网[W-Tr5z_3U
}
w4RK(g(] eqr0error()
'|p p8LEb0{
,l4`L%k.Tc t0  # print an error and exit51Testing软件测试网8EJf pcq-Q&_
  echo "$1"51Testing软件测试网(g`z8_(K'?0J
  exit 151Testing软件测试网I _P1{ ?QPug
}51Testing软件测试网$s7S.hJ Z3iM.Z w
lastchar()51Testing软件测试网1i`@ X)|+A\:\
{51Testing软件测试网7lJ'r9^T6v
  # return the last character of a string in $rval
-V8B+b1~"AP/rgTi0  if [ -z "$1" ]; then51Testing软件测试网 X4P'S+K8[
    # empty string51Testing软件测试网/j%j0}d]K `pt YYw
    rval=""
XSe$P+^t0    return51Testing软件测试网&c']!@(\8?
  fi51Testing软件测试网 v%Os,_/sg4xa O
  # wc puts some space behind the output this is why we need sed:51Testing软件测试网%p#I#Y g#?3b]]y
  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
c?IG ^d2^3R%J0  # now cut out the last char51Testing软件测试网{O"UW+Wq GC
  rval=`echo -n "$1" | cut -b $numofchar`51Testing软件测试网e)OB'_ d
}51Testing软件测试网i@(G&Zb:Iq
chop()
:} I"E8O|0{
d k'][6?&E L[0  # remove the last character in string and return it in $rval51Testing软件测试网0sc"aM7C0@]+W1{&v!d
  if [ -z "$1" ]; then51Testing软件测试网3bb,Vu6g$j g0l_ VC
    # empty string
j8f"m3hCP/x0    rval=""
@$[HP4N8Y|/a0    return
w+O!K iZI0  fi
`dj,u$^-s&~0  # wc puts some space behind the output this is why we need sed:
],mWewO-kH!z ?N0  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
?#y:Zw| _.d1K0  if [ "$numofchar" = "1" ]; then
eqa0Z9h { s!B0    # only one char in string
5C@.o WL9|[0    rval=""
C B6KLY0    return
K3t3rj;dI1iN0n0  fi51Testing软件测试网mn$c+fW J
  numofcharminus1=`expr $numofchar "-" 1`
V ~yKY \W,^.bB0  # now cut all but the last char:51Testing软件测试网(t @%d,kM6p
  rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`51Testing软件测试网'cy|I$e,b^UW
}
^K1Ba PD*Zq,d0while [ -n "$1" ]; do51Testing软件测试网)O/e@1c:cGZ9?DsL
case $1 in51Testing软件测试网5v}Jmf:u
  -h) help;shift 1;; # function help is called51Testing软件测试网)KJAM5i0eLY
  --) shift;break;; # end of options51Testing软件测试网5gF5v-y"t,qD
  -*) error "error: no such option $1. -h for help";;
oHsPA0  *) break;;
P0^"H SL/i$I)_f#i0esac51Testing软件测试网"l5{*gQ~U
done51Testing软件测试网6q:G.E3]-F ~I
# The main program51Testing软件测试网8H"oj/fa cvY
sum=0
bn5Z{G6xp0weight=1
'^,C9Z3I]g8U0# one arg must be given:
~^7l c5]P`z#^fP0[ -z "$1" ] && help
nHut0T$G+L}Ue0binnum="$1"
[wx;B&Le f+P](bhu0binnumorig="$1"51Testing软件测试网Kq K%K0}-|"d r#vF
while [ -n "$binnum" ]; do
i*F)s7u o8^0  lastchar "$binnum"51Testing软件测试网fkC4Wq(R x5i-^
  if [ "$rval" = "1" ]; then51Testing软件测试网9b:s \5Ko#gSK5p
    sum=`expr "$weight" "+" "$sum"`
,ew:wpe`)N0  fi51Testing软件测试网"A QU R$ut#NU6_I"P
  # remove the last position in $binnum51Testing软件测试网1lTH!n#nXO/s
  chop "$binnum"51Testing软件测试网0i6zcn$N:`p%WA
  binnum="$rval"
P:m%dY$tz(Zj0  weight=`expr "$weight" "*" 2`51Testing软件测试网Z$Z bgn1}g
done51Testing软件测试网tR9?1z fg
echo "binary $binnumorig is decimal $sum"
:Dp1egf,x-L0   该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制:51Testing软件测试网{i)heHRNv ]
0 * 1 + 1 * 2 = 251Testing软件测试网C^5t3B*YNp/e
  为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字符。
Er&^/q l&`-^2r(j0r0    文件循环程序51Testing软件测试网9bY^CA
  或许您是想将所有发出的邮件保存到一个文件中的人们中的一员,但是在过了几个月以后,这个文件可能会变得很大以至于使对该文件的访问速度变慢。下面的 脚本rotatefile可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1,而对于outmail.1就变成了outmail.2 等等等等...
qa'F)Z5p$m Q0#!/bin/sh
2R(A3\&O+[0w D5Kb0# vim: set sw=4 ts=4 et:51Testing软件测试网 Pm ["\ q5c
ver="0.1"
m$lgj4c.}5SY0help()
oS_L ]\0{
h2T b#jg c(tDS0S`0  cat <51Testing软件测试网2idVd*[S Hs
rotatefile -- rotate the file name
5Y7O/O"IY0i"H3_8r:h0USAGE: rotatefile [-h] filename51Testing软件测试网 M1?e0l/j$k5n S
OPTIONS: -h help text51Testing软件测试网 kyhy*tJ*b*ve
EXAMPLE: rotatefile out51Testing软件测试网7lxE9^-x$iOs
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1
A3zbp2R2?G0and create an empty out-file51Testing软件测试网 pb+E+M3x9W
The max number is 10
P1c4Y.R` B&j0version $ver
"[1Y|6G];f0HELP51Testing软件测试网;R2\ S#G S8T2m e
  exit 0
Q&hYz/k2@;sf/v0}
u mI,n7tO w0error()51Testing软件测试网?/a$a%g8q%C^d*]
{
7}'s R ]`]z&P*`0  echo "$1"
:K \bz AOIR&m6oY w0  exit 1
6R q2}_+T\0}
2ot%pA0P;wY0while [ -n "$1" ]; do51Testing软件测试网!q6A#W{,z1_2G
case $1 in51Testing软件测试网$@"s-_0b6~{7O J
  -h) help;shift 1;;
4y ~ s6XMlo0  --) break;;51Testing软件测试网P6J?K `G-A:]
  -*) echo "error: no such option $1. -h for help";exit 1;;
Z0ivQ1og0  *) break;;
|.^] @S U!p-s0esac
{%P f&?;BE$J(}0done
Q)p1g{GT"X1V0# input check:51Testing软件测试网 g7CI\ R,t
if [ -z "$1" ] ; then
WW2|E]mK*Q0error "ERROR: you must specify a file, use -h for help"51Testing软件测试网a'H'J*`!iR\g
fi51Testing软件测试网*Kd\tb;H
filen="$1"
,d+I4QrVv b0# rename any .1 , .2 etc file:
Cdq*N6E5k1P0for n in 9 8 7 6 5 4 3 2 1; do
Ymz&H-\3lia0  if [ -f "$filen.$n" ]; then51Testing软件测试网m3o1i3U7ki:q
    p=`expr $n + 1`51Testing软件测试网UQN3T)m0F1I
    echo "mv $filen.$n $filen.$p"
3t3[jTY!d0    mv $filen.$n $filen.$p
1K7o q Js'T2o0  fi51Testing软件测试网1rK C"hB}6k
done51Testing软件测试网 J{ fV i+hb(KLa
# rename the original file:51Testing软件测试网9y"T:E rW
if [ -f "$filen" ]; then51Testing软件测试网o:v%H0Bz F*d$X2t_&]
  echo "mv $filen $filen.1"51Testing软件测试网Yu)X5L,SY
  mv $filen $filen.151Testing软件测试网r u:Jrf+~"e$B} N3wh#B
fi
Cn0uc-D%oTW"Hi0echo touch $filen
Td z?.i`E0touch $filen
Fv1Cb$\0  这个脚本是如何工作的呢?在检测用户提供了一个文件名以后,我们进行一个9到1的循环。文件9被命名为10,文件8重命名为9等等。循环完成之后,我们将原始文件命名为文件1同时建立一个与原始文件同名的空文件。51Testing软件测试网#\u er@7fV
调试51Testing软件测试网3k}n1vX*xf(PJ J
  最简单的调试命令当然是使用echo命令。您可以使用echo在任何怀疑出错的地方打印任何变量值。这也是绝大多数的shell程序员要花费80%的时间来调试程序的原因。Shell程序的好处在于不需要重新编译,插入一个echo命令也不需要多少时间。51Testing软件测试网"r4l&@-MAIdw
  shell也有一个真实的调试模式。如果在脚本"strangescrīpt" 中有错误,您可以这样来进行调试:51Testing软件测试网$V w1uCZ
sh -x strangescrīpt51Testing软件测试网!G0Wk\A@&x
  这将执行该脚本并显示所有变量的值。51Testing软件测试网az:f5W8FT*|$B^ iA
  shell还有一个不需要执行脚本只是检查语法的模式。可以这样使用:
Y8{6k N|0\JT5lt0sh -n your_scrīpt51Testing软件测试网sC#A$S@
  这将返回所有语法错误。51Testing软件测试网 IM:_9s-d b-c/q

TAG:

 

评分:0

我来说两句

Open Toolbar