Linux Shell编程(基础教程)

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

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

#ID;^a*@*nu01. Linux 脚本编写基础51Testing软件测试网p(|9B.EG
1.1 语法基本介绍
C,^2L)J9aD9M01.1.1 开头51Testing软件测试网 YcP,H%lH%~
       程序必须以下面的行开始(必须放在文件的第一行):51Testing软件测试网s$qnTpc/tAF}w
       #!/bin/sh51Testing软件测试网$T8mY5QL*G
    符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。  当编辑好脚本时,如果要执行该脚本,还必须使其可执行。51Testing软件测试网9^7A(A8^B }@-tfZD
    要使脚本可执行:   编译 chmod +x filename 这样才能用./filename 来运行
TI)ZtN2O01.1.2 注释
X?4w AjO]aG C0  在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。
IK}2j?f6c01.1.3 变量51Testing软件测试网WO~*d5q,h7u O
  在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写:
1n b;B)w@$eW.U.E0IJ0        #!/bin/sh
OQp-c5j"}N0        #对变量赋值:51Testing软件测试网,G p+~"nv"m-IX:lZ
        a="hello world"
x:L$PlV,W4L0        # 现在打印变量a的内容:
YH2^$V mh2k7M}0        echo "A is:"
a#X OO?!j R|0        echo $a
6Fx!gO9|8u0       有时候变量名很容易与其他文字混淆,比如:
R~4Njf0        num=2
Sq"n R(uP3a0        echo "this is the $numnd"51Testing软件测试网E{f#ya.A w~
       这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:51Testing软件测试网 h!}:M c/^qZ].G
        num=2
-nsdZV&IS&}0        echo "this is the ${num}nd"51Testing软件测试网7O ?$o8Sg
        这将打印: this is the 2nd
R%T*OD!x$Q#a&V7L01.1.4 环境变量
4Y-MI_:a0       由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录51Testing软件测试网s%\keR M7M-zX5L
脚本中使用环境变量。
},x |_['R Av01.1.5 Shell命令和流程控制51Testing软件测试网$Oa w3VAu E8S
       在shell脚本中可以使用三类命令:
$rqa(?S"o\0       1)Unix 命令:51Testing软件测试网$d~*mci/YT)e
      虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来进行文件和文字操作的。
D,l9IU;W0        常用命令语法及功能
&nV]6lm f1ft0  echo "some text": 将文字内容打印在屏幕上51Testing软件测试网?;})L a%@n\
  ls: 文件列表51Testing软件测试网 Aa@2W0?Q_
  wc –l filewc -w filewc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数51Testing软件测试网h*N/BF%OUIk0z(a
  cp sourcefile destfile: 文件拷贝
'o^ d;]s#zE0  mv oldname newname : 重命名文件或移动文件51Testing软件测试网K{"[2R7O2i_
  rm file: 删除文件
?o-B:aE3dVmQ(T0  grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt51Testing软件测试网X5s5Js5`el,T\I
  cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,这是两个完全不同的命令51Testing软件测试网-pz:t$b*W0@n
  cat file.txt: 输出文件内容到标准输出设备(屏幕)上51Testing软件测试网 B-h n7FL$K
  file somefile: 得到文件类型
_t0C$i*] {{K[&sw0  read var: 提示用户输入,并将输入赋值给变量
X}-tN]SF0  sort file.txt: 对file.txt文件中的行进行排序
g;N8QP;{1Lz0  uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq51Testing软件测试网X;d"BoE6\0^9mE
  expr: 进行数学运算Example: add 2 and 3expr 2 "+" 351Testing软件测试网0E!xo0|;A/C%h
  find: 搜索文件比如:根据文件名搜索find . -name filename -print51Testing软件测试网-m:T T-U9C[
  tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile
2Frr t"o1r r0  basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux
_o,fC H*F-J @L0  dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin
7KQ*z'`%{3kA0  head file: 打印文本文件开头几行
r/hb&yw4ik)L0  tail file : 打印文本文件末尾几行51Testing软件测试网T`._6Kw Mn
  sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。不要和shell中的通配符相混淆。比如:将linuxfocus 替换为LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
M p6`z&Cz0  awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。51Testing软件测试网9cVABI
cat file.txt | awk -F, '{print $1 "," $3 }'这里我们使用,作为字段分割符,同时打印第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA
~3?@3vG ja }7d%M0        命令输出结果为:Adam Bor, IndiaKerry Miller, USA
$Ks{t]8sJ r8bA0        2) 概念: 管道, 重定向和 backtick51Testing软件测试网HW*v'K"oN,V
  这些不是系统命令,但是他们真的很重要。
8M+[.b?s\0  管道 (|) 将一个命令的输出作为另外一个命令的输入。51Testing软件测试网pA!t1x Uhc'Jj)l
                 grep "hello" file.txt | wc -l
u!O M Q {]0  在file.txt中搜索包含有”hello”的行并计算其行数。
JMZ&MY!L;j0v%N%i0  在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。
2{saH,[R?0  重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。
izN0Va0      > 写入文件并覆盖旧文件51Testing软件测试网q:X0W.`!ms R;^4R J
      >> 加到文件的尾部,保留旧文件内容。
P#Y4X rASN+r!v,u]I0        反短斜线
J#].S}5?0     使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。
5xW/VZr#J P%~L uZ0         命令:
'I8CTU#c0           find . -mtime -1 -type f -print51Testing软件测试网.vwV9~|$w
     用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您想将所有查找到的文件打一个包,则可以使用以下脚本:
z.FSPG8i"L.}[0             #!/bin/sh
+{/u5C7?DxO#v0             # The ticks are backticks (`) not normal quotes ('):
#e z-T,}1}0              tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`
*K!LW-v8ma0       3) 流程控制51Testing软件测试网;_E4]QeJR W
        1.if51Testing软件测试网j5{*_ V2z7H
    "if" 表达式 如果条件为真则执行then后面的部分:
J,W n2t%@0[2J0            if ....; then51Testing软件测试网i'Yq@4n&[Y
           ....
XaR(QbL&b%Wav0           elif ....; then51Testing软件测试网y1T8pn+kr
           ....
@ j0^;~7|0           else
:e;|'Z1|0Ce0           ....
i,i'w2H5l0           fi
#@"l&G'@| G&Rs3~ }0           大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等…
;d/P HdT[0    通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。
sdK'c4A0                 [ -f "somefile" ] :判断是否是一个文件
z;q:KM1Q [0                 [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
4H1w$s(FH#B(@ Q0                 [ -n "$var" ] :判断$var变量是否有值51Testing软件测试网4cjc2DG)W,x
                 [ "$a" = "$b" ] :判断$a和$b是否相等
U N$wN y fU0    执行man test可以查看所有测试表达式可以比较和判断的类型。51Testing软件测试网y,E-{/Eha [t4Wf
   直接执行以下脚本:
r0g yR2{/?Y v0               #!/bin/sh
,_;h#{0s.i0               if [ "$SHELL" = "/bin/bash" ]; then
roDA!L#D$g0                    echo "your login shell is the bash (bourne again shell)"51Testing软件测试网8rT-[2y+m X5gd%^
               else
+q"si*hTX-{/E:C:M0                    echo "your login shell is not bash but $SHELL"
y*lT'i^ J_ s%`0               fi
"P kLk3S7C;\0   变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。51Testing软件测试网 j1j%[ d8N(k$n#h0`J_
       51Testing软件测试网qI_L'o+X
        快捷操作符
)^%JZ$S3c z0        熟悉C语言的朋友可能会很喜欢下面的表达式:
L }Gr6W k0~_0                  [ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"
c9O x+y{T7a!N0  这里 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在则打印” This computer uses shadow passwors”。同样或操作(||)在shell编程中也是可用的。这里有个例子:
{9dZtl.XAD0                 #!/bin/sh51Testing软件测试网"p}q8s:u
                 mailfolder=/var/spool/mail/james51Testing软件测试网RDNK0Y%lM
                 [ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" ; exit 1; }51Testing软件测试网)o @xR!lYs"T9[w
                 echo "$mailfolder has mail from:"51Testing软件测试网 b a4^0r/aR&gR-k6J
                 grep "^From " $mailfolder51Testing软件测试网3f }5~cl4r
        该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令:
#\s:m6?3d M] q0  -打印错误信息
lo s1MAH^&W;^Y+up0  -退出程序51Testing软件测试网T-S0_"I bWLd7n&z
  我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。
nc]\wY0  不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。

m|:|Z8e2[d7y r051Testing软件测试网(c#U7~0T]l{r

         2.case
.z|z8B$B9T(Jq&n o0               case :表达式可以用来匹配一个给定的字符串,而不是数字。
D}+{&aA LP2v0                      case ... in
&C7Q dL,l^x d4s h#}/O0                            ...) do something here ;;
?lm+BZ%p`F0                      esac
2YW3alf8N0         让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:51Testing软件测试网J}Y/_t%z-uTW%Fc I
                     file lf.gz
1w4tU3lO0l.vX0                   这将返回:51Testing软件测试网9R9v m-svgG(t3f+`
                         lf.gz: gzip compressed data, deflated, original filename,51Testing软件测试网m/^o B g%D4ga
                         last modified: Mon Aug 27 23:09:18 2001, os: Unix
p P2WI D/ZyH$@0             我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件:
P$sW g*Ym!Ren` N0               #!/bin/sh
"X;n\4Sb-uDD:i3b0               ftype=`file "$1"`
4Y(pnj4z2O9UC0               case "$ftype" in51Testing软件测试网f:~D rxI5~7d
                       "$1: Zip archive"*)51Testing软件测试网^BIPB ^Xj
                  unzip "$1" ;;
(P1y2i mFMH0                         "$1: gzip compressed"*)
@SL'T,\6X}0                    gunzip "$1" ;;51Testing软件测试网)LV Ih}fUU
                          "$1: bzip2 compressed"*)51Testing软件测试网0k"u$Q&ys.dX
                     bunzip2 "$1" ;;51Testing软件测试网[Z[8W?q1M ^
                           *) echo "File $1 can not be uncompressed with smartzip";;
2js:[r2neJ0                esac
A|.Ps'}2O0         您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。
-cG2`/r:Yd_ @0也就是说,当我们运行:51Testing软件测试网v(n H1n^(G1JP
                    smartzip articles.zip51Testing软件测试网-iFd,n3qh6N
                    $1 就是字符串 articles.zip
n3?!lO if0                3. selsect51Testing软件测试网(E%a!L\&Y[ bm
                  select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。51Testing软件测试网;V%[;P9z d-l7y?
                    select var in ... ; do
)|fd0u*k/l9k0                         break51Testing软件测试网I;ML0Z%Y*K q
                            done51Testing软件测试网5k*H1fa.ch V&s
                            .... now $ var can be used ....51Testing软件测试网 {@(?s6G
                   下面是一个例子:
xC+r p|0x0                         #!/bin/sh
'M`;Xux-H0                         echo "What is your favourite OS?"
4[},z5w8w0                         select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do51Testing软件测试网V5k.z*JV"`P|)W
                    break51Testing软件测试网:na?*s7ty6B
                                done
)ej[!?,Q/l.bU-i0                           echo "You have selected $var"51Testing软件测试网,v`0t AsSsuW
              下面是该脚本运行的结果:
(m8y9{v!?Y\0                               What is your favourite OS?
)n~-\x7RFO0                                    1) Linux51Testing软件测试网OG6Vq5M1Vhw.w1W$`
                                    2) Gnu Hurd51Testing软件测试网4Zv:E Pz8uGQu(E
                                    3) Free BSD51Testing软件测试网7|"pu4B0i$I
                                    4) Other
;I1k7j/i"j\ [W0                                  #? 1
!H"oNVfYnD0                                You have selected Linux51Testing软件测试网$gY?e.J+B#st
         注:var是个变量,可以换成其它的值。break用来跳出循环,如果没有break则一直循环下去。done与select对应。51Testing软件测试网3l0oa:kH6^'TCO
                  4.loop51Testing软件测试网IED:_f-N
                      loop表达式:51Testing软件测试网$M,|YX2U P;@~J
                            while ...; do
v;Df;@Z[7b N8J0                                      ....51Testing软件测试网~?AlR4T` uM
                               done
"v?9uo2aA U0             while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true.
sJN }Q!?0关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。
CY0swcT I6o e0  51Testing软件测试网8QDa'k@4RR F W
                     for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量:
0f-h;?i'fTF0                          1,   for var in ....; do51Testing软件测试网!{\OmQ4{
                                 ....51Testing软件测试网*w{~e3^_!Z
                                done51Testing软件测试网e7S.y6ML+NV8L
                       在下面的例子中,将分别打印ABC到屏幕上:51Testing软件测试网*ojS N's V8p N
                            #!/bin/sh51Testing软件测试网pzP }I9]5RXD
                                    for var in A B C ; do
-aEX6J.JC h"?$~0                                 echo "var is $var"
)\v*wy+v@ j0                                     done

4ShL%]Ba/{0

*g&P&cl(s(]D1D4}8B0                           2,   for (( 条件一; 条件二; 条件三 );do51Testing软件测试网f.E r.Osx!M| p1@
                                ...51Testing软件测试网{ JU7dl@0P
                                done51Testing软件测试网/H2DzX~(b
                        例:51Testing软件测试网#zo:\ {JRc
                     51Testing软件测试网3fq3p0A*@c
                   for ((i=1;i<10;i=$[$i+1]));do51Testing软件测试网 Z&N W7dD._ X$W.J

51Testing软件测试网"oW N!Q3lsJ1@

                             echo "a"
)]Sw Y-k$?2j}0                          done51Testing软件测试网ki;[h$O6o
输出:

m zFYR%]051Testing软件测试网:Z$U7Ps q?*i.G

a
+nj\7f.WX3s*c0a51Testing软件测试网:~&Wl4jaa2E
a
dd-x*x9HJV2a o0a51Testing软件测试网DW.L*s/`$R k@0F
a51Testing软件测试网2R@|,y*`
a51Testing软件测试网 j)q m f,@5~ce;|@
a51Testing软件测试网:D(n\QY%~7Dm
a
+s#M*Go0xr0a51Testing软件测试网8a(aujO\Op T

i7q;c@pW0条件一:这可以看成是『初始值』,如上面的例子中,初始值是 i=1 啦!51Testing软件测试网;G\TnI4}.F1M
条件二:这可以看成是『符合值』,如上面的例子中,当 i<=100 的时候都是符合条件的!51Testing软件测试网@~.bKQ|3}4aW S
条件三:这可以看成是『步阶』!也就是说, i 每次都加一! 所以啦!上面的例子是说:由 i=1 开始到 i<= 100 ,每次 i 都加一来执行底下的程序段(就是 s=s+i ),当 i >100 (也就是 i=101 )就跳出这一段程序段!怎样!不难吧!51Testing软件测试网&Q8^+IP9O X9GO4N;]J

z-F1T^_DA5j4a.p0 51Testing软件测试网%mIYpU`Y|-rJ

J+C"_3Dr!M2[;M[ m2T4hW051Testing软件测试网0j&JE |q9y
                        下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:
~AEqFO#t@0                          #!/bin/sh51Testing软件测试网&P d${5Q\ f0h6o
                          # list a content summary of a number of RPM packages51Testing软件测试网_]-w%`0ap
                          # USAGE: showrpm rpmfile1 rpmfile2 ...
w7l4I8I6R,[9E0                          # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm51Testing软件测试网!Y,GN ~"fT
                            for rpmpackage in $*; do
3Qs dazlB2{0                         if [ -r "$rpmpackage" ];then
vXb~m'D`8y J7n0                         echo "=============== $rpmpackage =============="
K5k eM9UL7n0                          rpm -qi -p $rpmpackage
c~]*B8A5n ] Z0                          else51Testing软件测试网:_YXk3T)? Q)L
                           echo "ERROR: cannot read file $rpmpackage"51Testing软件测试网"Q I:_iho9c+F
                         fi
1jG3O4H2cJ"i.f0                              done51Testing软件测试网6W}!~h/M1^.~ i
                   这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。
/}~G H8@7R9z0                        如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm
eg2^O(\,v^0                                   此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.

~^7{9Q ]0

zu)QR|a0 

O&NEv$R8y#S ]"w051Testing软件测试网5T F9[c3z

『until:直到条件相同的时候才离开程序』;51Testing软件测试网W/nX;H)s4^
『while:当条件相同的时候,就继续做!』 

:OV pkZ]2m,d0

u+? fcV4n&V'mQ:@0until [ condition1 ] && { || } [ condition2 ] ...51Testing软件测试网9f {2G6C(w$e.X-R

51Testing软件测试网x+OTL/wxx`

 51Testing软件测试网.n}ql_)g

51Testing软件测试网4o:GW re7d~P8b


9hH-^0SCq$LR0                 5. 引号51Testing软件测试网ss9[R"f$V,L
                   在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符(比如*)替换成合适的文件名,它变量替换成变量值。为了防 止程序作这种替换,您可以使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件, mail.jpg 和tux.jpg。
H.d@xmCP0          编译SHELL脚本51Testing软件测试网8wzw6W6e
          #ch#!/bin/sh mod +x filename51Testing软件测试网 R/q*}-u?(zU.TS7x:i
 cho *.jpg       ./filename 来执行您的脚本。51Testing软件测试网N+B9YVt]N9y
  这将打印出"mail.jpg tux.jpg"的结果。
$i7lo,zE0    引号 (单引号和双引号) 将防止这种通配符扩展:51Testing软件测试网~B/ho lqr@N
             #!/bin/sh
j-R-e*b k0             echo "*.jpg"
+c7NU:^6y/b0             echo '*.jpg'
nw'LfX#tE0  这将打印"*.jpg" 两次。
&F^UK:@#Q X0  单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。
9Rh4{"o7D0         #!/bin/sh51Testing软件测试网)H[PA m$r
         echo $SHELL51Testing软件测试网AU+e N*Rs3Q5i
         echo "$SHELL"51Testing软件测试网@4Sk-f%Y
         echo '$SHELL'
q%h5@'?PZ6CII0   运行结果为:51Testing软件测试网R/k7pz(@`"gB#`
             /bin/bash51Testing软件测试网iri Ve8I
             /bin/bash
+R.]-Y-gG6ZI0             $SHELL51Testing软件测试网 c#t2Qz#nxoj
  最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:51Testing软件测试网q0J.q(IO1MUK&j
           echo *.jpg
/i~0zoG;F7je m0           echo $SHELL
J%e!VP6] T`0  这将输出:
cP;Fr7[j0           *.jpg
Vm/H(Q A1^ h(l g0           $SHELL
UXJrD]:E7N0         6. Here documents51Testing软件测试网b zrG2h1f
          当要将几行文字传递给一个命令时,here documents(译者注:目前还没有见到过对该词适合的翻译)一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents就不必用echo函数一行行输出。 一个 "Here document" 以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:51Testing软件测试网i1IQ,E |
         #!/bin/sh51Testing软件测试网f$qLJ.lE
         # we have less than 3 arguments. Print the help text:51Testing软件测试网:B;Ascl drm
            if [ $# -lt 3 ] ; then
+rQR}'u9pe6Y,|0                 cat <
Jg(ltO*v0                 ren -- renames a number of files using sed regular expressions51Testing软件测试网'I^ Wg X~
                 USAGE: ren 'regexp' 'replacement' files...51Testing软件测试网;O;}'o!x'n J
                 EXAMPLE: rename all *.HTM files in *.html:
f1L*Vtq R%O0              ren 'HTM$' 'html' *.HTM
uDo:{ w'_-\9~5W0                 HELP
U'jF9e:^XhE UZ0              exit 0
'HiZfGKJQ0            fi
2lZ{ k6e+Xnxu S0            ōLD="$1"
o i9TOZl0            NEW="$2"
c)]6j h)@ lx&f0          # The shift command removes one argument from the list of51Testing软件测试网K4Y?:L0f*g
          # command line arguments.
/MT:iT"A(?,QxbY0          shift
6m] RY&eU3[jl0          shift51Testing软件测试网#K#W(~+v0F'T
          # $* contains now all the files:
)C!Hgs/W2LW0         for file in $*; do
$f(cxU#F Vg zB0          if [ -f "$file" ] ; then
j%ml^8{g0             newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`51Testing软件测试网(AOZiPV`!hCj
             if [ -f "$newfile" ]; then
!M#@8qquS(|9W#p0                  echo "ERROR: $newfile exists already"
~Q&Rh:~Z'D!I_'} S5z8B0             else51Testing软件测试网 urJ/|!ngZ;to0d
                  echo "renaming $file to $newfile ..."51Testing软件测试网"}P4C5bi"lt
                  mv "$file" "$newfile"
5c;EJPN*t H,k0              fi51Testing软件测试网z1wZY%N1n9\8I*~ yj
            fi51Testing软件测试网:B.Bz)u3{ |a
           done
$ya-Wh#Y[+a0        这是一个复杂一些的例子。让我们详细讨论一下。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。 如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从 参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我 们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目 的:得到了旧文件名和新51Testing软件测试网0@3~;e W2s\Z{H
文件名。然后使用mv命令进行重命名。51Testing软件测试网3N4O*_ B6q
          4)函数51Testing软件测试网2Y a}^8E0j]
             如果您写了一些稍微复杂一些的程序,您就会发现在程序中可能在几个地方使用了相同的代码,并且您也会发现,如果我们使用了函数,会方便很多。一个函数是这个样子的:51Testing软件测试网 Ls,X[Bd;w0C
          functionname()
Y3pt$f/W(RR'm)`0          {51Testing软件测试网c:V~j D u0WV[/[
                 # inside the body $1 is the first argument given to the function
De&}t Ba0                 # $2 the second ...
e \oc7G"D }0D kP2g0                             body51Testing软件测试网wx/M-i F![QM7k6w
            }
n0~2Q l2{%i*I7F)W0          您需要在每个程序的开始对函数进行声明。51Testing软件测试网-M+m+np#}-|&d,N
   下面是一个叫做xtitlebar的脚本,使用这个脚本您可以改变终端窗口的名称。51Testing软件测试网-m,xJ [`\sI
           这里使用了一个叫做help的函数。正如您可以看到的那样,这个定义的函数被使用了两次。51Testing软件测试网 y{ann
               #!/bin/sh51Testing软件测试网4Z)~u,X/g*[
               # vim: set sw=4 ts=4 et:
{k}!WN/N A'Pu0               help()51Testing软件测试网5d }NU*~+w]A"@
               {
%X4cSp LKaLx+W0              cat <
|)O"PV8c0]0                     xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
_7{2un,k;KK2vv0                     USAGE: xtitlebar [-h] "string_for_titelbar"51Testing软件测试网:n8r%Uk(_2mJ'GWYC(Q
                      OPTIONS: -h help text51Testing软件测试网l3_ A5}5s7u R%K
                     EXAMPLE: xtitlebar "cvs"51Testing软件测试网 V'kK%d @
                     HELP
| { l?*ku0             exit 051Testing软件测试网8wtq&n9A+Zj} O
               }
|s/aa [gw2}@"P0               # in case of error or if -h is given we call the function help:51Testing软件测试网0J"Yj|Bu%z/u:y%\D
               [ -z "$1" ] && help
~K { j6f [ D {]0               [ "$1" = "-h" ] && help
KR/BL1CZ2w0               # send the escape sequence to change the xterm titelbar:
mmJYs\0i*T"qFW0                 echo -e "33]0;$107"51Testing软件测试网u8|4TSM
                #
c2Wt(r)I0            在脚本中提供帮助是一种很好的编程习惯,这样方便其他用户(和您)使用和理解脚本。51Testing软件测试网%le4vP!?p"}q
        命令行参数
lHaN)Q)X,in b5e0  我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。 但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (比如文件名)。有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无遗是一个不错的方法。51Testing软件测试网Pf:fy p5T
         #!/bin/sh51Testing软件测试网+F*z"K Q$@.[
         help()51Testing软件测试网&G!|:femF3| C
         {51Testing软件测试网u-zZ&|A{$G
            cat <
Y*PQ&c9k,Cb wC0               This is a generic command line parser demo.51Testing软件测试网.spe'\J%Xp6d
               USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile251Testing软件测试网%n,N&A!qzzc
               HELP51Testing软件测试网,Yj5] cs7ac(I
            exit 051Testing软件测试网1S4m0kf O }B
         }51Testing软件测试网~$O/vfv
          while [ -n "$1" ]; do51Testing软件测试网LM@sxul0lN
        case $1 in51Testing软件测试网S9[fr(Lh
       -h) help;shift 1;; # function help is called51Testing软件测试网_em/a'H
       -f) opt_f=1;shift 1;; # variable opt_f is set
%R,b{o x8|&O0        -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
?#VX0hwc0        --) shift;break;; # end of options51Testing软件测试网!lbf#O _|6ixi
       -*) echo "error: no such option $1. -h for help";exit 1;;
P+p/l?A^Z0       *) break;;51Testing软件测试网aPv3bOk
          esac51Testing软件测试网&_){NFQ9A a_1b1Ic%k$P
          done
2t{(i.z'{ h2I"o0          echo "opt_f is $opt_f"
6]:R7Q;pe4N0          echo "opt_l is $opt_l"
bf6s-UTI`0          echo "first arg is $1"51Testing软件测试网] x?z:`e"Nbv+EU
          echo "2nd arg is $2"
#umI!Qmb&W/~0  您可以这样运行该脚本:51Testing软件测试网$Q]g3s*k:pv)N'p&y
                 cmdparser -l hello -f -- -somefile1 somefile251Testing软件测试网)FVGF4dfL1w
  返回的结果是:51Testing软件测试网'Q"dF ~3p'm c
             opt_f is 151Testing软件测试网kT2sn$b&LOTd
             opt_l is hello51Testing软件测试网$i y&@3ow
             first arg is -somefile1
+KXh1w HSu0             2nd arg is somefile2
aJ5XKU~~I0  这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数.51Testing软件测试网f]1`*f1K'V#saT

W(RO cT'u,e051Testing软件测试网KW8X+lzaH
第2部分 实例51Testing软件测试网4nNXyx(v

51Testing软件测试网FNskb+?X8] tY

    现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下copy命令:
.D8G!KI j1]0cp framework.sh myscrīpt51Testing软件测试网 ZXw4r#e-[!n
 然后再插入自己的函数。
0pm7@9Ot^ x0  让我们再看两个例子:51Testing软件测试网4X0Ws@|:lM!V\$|
  二进制到十进制的转换
C3{PL5B0  脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:
}3mG_!M"e m#J5Vy:Q*]0#!/bin/sh51Testing软件测试网 ES G,f.K1fSi
# vim: set sw=4 ts=4 et:51Testing软件测试网$SW? oB#GbONxmh
help()51Testing软件测试网+?qX?-c2W b*`
{51Testing软件测试网 hi]%M/d!o P G
 cat <51Testing软件测试网2X9d+m$UE;k2Pa,F
b2h -- convert binary to decimal
aA6@1ET$i_ f;ak0USAGE: b2h [-h] binarynum
4_(kv5HL+u }`0OPTIONS: -h help text51Testing软件测试网2T*k8AC1\)C4sp
EXAMPLE: b2h 11101051Testing软件测试网 NF'~8J nKN
will return 5851Testing软件测试网 Mvi$A~7] g
HELP
y;L'POI!q#d0 exit 051Testing软件测试网ei'Vx,AIS1u
}51Testing软件测试网+QpbU!Qk"CPp
error()51Testing软件测试网/UL J"\ y"G [qs+fj
{51Testing软件测试网{R_,E AZM1I4T5t^
  # print an error and exit
$G4@.i!T7Q/g0U4p{_ D0  echo "$1"51Testing软件测试网%AW U|N%] S'_TZ
  exit 151Testing软件测试网7X(Am'q$j#n1@%Y|
}51Testing软件测试网vI.I S`/]
lastchar()51Testing软件测试网*I9C2md I
{
K6BF q9p?q!x0  # return the last character of a string in $rval
X$e!p0~-w1U;^0  if [ -z "$1" ]; then
(CEO3Z1s2]P0    # empty string51Testing软件测试网.b'WBwj G k
    rval=""51Testing软件测试网(Y@&_S:hp|D
    return
3lO+q8qh6QnNp0  fi51Testing软件测试网\8r'l_d GaB I
  # wc puts some space behind the output this is why we need sed:
ac`*R1Z/?d2BG0  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `51Testing软件测试网 X%b&k^ hp!t
  # now cut out the last char
O ee*Hj%h0  rval=`echo -n "$1" | cut -b $numofchar`51Testing软件测试网8Zb2X(iCdL b
}
x3H w t MI0chop()51Testing软件测试网1u#r\T9v8`,eQ
{51Testing软件测试网;T.d DvOO4`:q @
  # remove the last character in string and return it in $rval
9cHz? q0xT8e6O0  if [ -z "$1" ]; then
x3]0LvXb?@W0    # empty string51Testing软件测试网+R/L!Vx$w%p
    rval=""
Q o;D r%{$b0    return
N4y#qFBB0  fi
!i@E2e|n5TQ0  # wc puts some space behind the output this is why we need sed:
6v]3F1S gQ"U0  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
)oZ0]9~0p"HP0  if [ "$numofchar" = "1" ]; then51Testing软件测试网[M$N1vV
    # only one char in string
)@9B2\_XQ }]cw0    rval=""51Testing软件测试网(UL,WdoH
    return51Testing软件测试网:`7WE&n1Z
  fi
T0?%X;P m!U(wS0  numofcharminus1=`expr $numofchar "-" 1`51Testing软件测试网'Vefe-o~ HM
  # now cut all but the last char:51Testing软件测试网bK},J%U2QT
  rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`51Testing软件测试网5c@1dNo6p,~/}x1@
}
e1S1fj)e)atq;xJ2\0while [ -n "$1" ]; do51Testing软件测试网zT QqX7q]
case $1 in
jF5P/Pl vd,|v0  -h) help;shift 1;; # function help is called
/i&pvK&vvv0  --) shift;break;; # end of options
.T Uv|S.Ce0  -*) error "error: no such option $1. -h for help";;51Testing软件测试网g{T4x b/g0k6l(P8~x
  *) break;;51Testing软件测试网c+{S:u(]$q|:t
esac51Testing软件测试网#?\lpRkG:}
done
${a_,l1J7z0# The main program51Testing软件测试网*` j H4m*Kc
sum=0
)o"wU:p;A:D0weight=1
R`)}N$\:R4o5R0# one arg must be given:51Testing软件测试网.n&n@,bI m
[ -z "$1" ] && help
c!V)p} `nFn(y0binnum="$1"51Testing软件测试网&p.C[IFIO,i
binnumorig="$1"
.eHQ5H `,~ t/pu7}-^2g0while [ -n "$binnum" ]; do
*S,H%wXZ O_}N0  lastchar "$binnum"
1t(N'? [/Y"tF0  if [ "$rval" = "1" ]; then51Testing软件测试网%{|EsQ0n
    sum=`expr "$weight" "+" "$sum"`
TI _"TJ]H[5S0  fi
9PV{:N}/_,v9\/BL(u0  # remove the last position in $binnum
U[.T1yMV^0  chop "$binnum"
,T6q&D7Y&r0_0  binnum="$rval"
)P f&X-U*V aA3GC `0  weight=`expr "$weight" "*" 2`51Testing软件测试网_3];e~;u3y |;N
done
iN~v;w)Yk+kYw0echo "binary $binnumorig is decimal $sum"
+Y:p s4mdh0   该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制:
"g'e4qv8OG7Ar00 * 1 + 1 * 2 = 2
r5h2L l8h%k5S0  为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字符。51Testing软件测试网Q-D~'\V5BS
    文件循环程序
7x'ieYE4@9Sz.z6A0  或许您是想将所有发出的邮件保存到一个文件中的人们中的一员,但是在过了几个月以后,这个文件可能会变得很大以至于使对该文件的访问速度变慢。下面的 脚本rotatefile可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1,而对于outmail.1就变成了outmail.2 等等等等...51Testing软件测试网h S+_#h1v|f
#!/bin/sh
2Y:b`"o5iDEb0# vim: set sw=4 ts=4 et:
Tw-q.Q?0ver="0.1"
s6eK M t\ mWz0E0help()
:ec}$n#m0{
/c'oeo.p4x!TQ9g}.]0  cat <
"{([oyC:c9}0rotatefile -- rotate the file name51Testing软件测试网.i C!R7EUZF
USAGE: rotatefile [-h] filename51Testing软件测试网8[9Wz@{LF
OPTIONS: -h help text
5sqj5V ]P,Rna0G0EXAMPLE: rotatefile out
*} c4U `?@w Ny1?0This will e.g rename out.2 to out.3, out.1 to out.2, out to out.151Testing软件测试网PCXln:j;c
and create an empty out-file51Testing软件测试网U\^-R?u5X
The max number is 10
(u%v'\KU0version $ver51Testing软件测试网/xW`T2m~"_
HELP51Testing软件测试网d1f0b7e&@5]cf7H*e
  exit 0
pFfvz0}
rz.K0u]L F0error()51Testing软件测试网 G^qy(E)YH
{
!| Y y;|1cS S,z0  echo "$1"
$Xg RHPYC&Z0  exit 151Testing软件测试网/e)M6B#s9{)N `KtR
}51Testing软件测试网0YE B+cnS&}
while [ -n "$1" ]; do51Testing软件测试网8Y&eGo:Ej3G },H4~
case $1 in
4pdO+p1i4B~0  -h) help;shift 1;;51Testing软件测试网S`E"vQH]
  --) break;;
4n [,W H^0  -*) echo "error: no such option $1. -h for help";exit 1;;
@1A4p#t ?2u%yw"`._h0  *) break;;
m CV9_ O0esac
9M6^rn5vtL0done
9I{ qfE1d(_:D Cj0# input check:
r9S W8`NY0if [ -z "$1" ] ; then
&du%~M2u UX8z0error "ERROR: you must specify a file, use -h for help"
'm ~zy!g4b0fi
S6{P E%S)}0filen="$1"51Testing软件测试网xW Jr)f'}#I.f
# rename any .1 , .2 etc file:
L3HNcAM aU/@0for n in 9 8 7 6 5 4 3 2 1; do51Testing软件测试网8Cm){k:mG)pW
  if [ -f "$filen.$n" ]; then
o2na V0G5L)Y0    p=`expr $n + 1`51Testing软件测试网!CK/Y*E:|@1tK1r
    echo "mv $filen.$n $filen.$p"51Testing软件测试网 jH9Vo\nw A){
    mv $filen.$n $filen.$p51Testing软件测试网?\xC;x6k+W%{
  fi
?F O_*K r5U4t0^0done
o rMRD-K4E;Kax0# rename the original file:
%k;T&E {3B0if [ -f "$filen" ]; then
n d{;B/O@(H2p sU0  echo "mv $filen $filen.1"51Testing软件测试网F6P hC&f
  mv $filen $filen.151Testing软件测试网x,|^ ?yz W
fi
MF~"ib5l0echo touch $filen
FK*|t7cS(~D0touch $filen51Testing软件测试网Q$J:|x'_jK5El
  这个脚本是如何工作的呢?在检测用户提供了一个文件名以后,我们进行一个9到1的循环。文件9被命名为10,文件8重命名为9等等。循环完成之后,我们将原始文件命名为文件1同时建立一个与原始文件同名的空文件。51Testing软件测试网^&s%vq|O
调试
`:d YL(bP0  最简单的调试命令当然是使用echo命令。您可以使用echo在任何怀疑出错的地方打印任何变量值。这也是绝大多数的shell程序员要花费80%的时间来调试程序的原因。Shell程序的好处在于不需要重新编译,插入一个echo命令也不需要多少时间。
)ghF"Y2Q"q%c3lr0  shell也有一个真实的调试模式。如果在脚本"strangescrīpt" 中有错误,您可以这样来进行调试:
v'T*`&c6v@$O0sh -x strangescrīpt51Testing软件测试网(b8UY Fb
  这将执行该脚本并显示所有变量的值。
md)G&KzV Q0  shell还有一个不需要执行脚本只是检查语法的模式。可以这样使用:51Testing软件测试网xD Y+SGb9a'w
sh -n your_scrīpt
})_T^ H2G$Csx(T^,l9S0  这将返回所有语法错误。

8uSG8Vv0

TAG:

 

评分:0

我来说两句

Open Toolbar