测试路漫漫, 吾将上下求索. 两年多开发经验, 六年整测试经验. 比较熟悉web自动化测试, especially in Ruby & Watir. 正在探讨Agile 测试, Junit testing in Agile. 联系方式:myfengliu@hotmail.com

转贴Linux Shell编程(基础教程)

上一篇 / 下一篇  2010-07-20 08:06:14 / 个人分类:linux shell

本文网址:http://bbs.bitscn.com/72875复制
5@(d&cBZ$Bg0
fu8r,`[` r)~2Q01. Linux 脚本编写基础
_\.v,Oz h ? R+e,^01.1 语法基本介绍51Testing软件测试网 Icp UuL
1.1.1 开头51Testing软件测试网6^j&a-e\p
       程序必须以下面的行开始(必须放在文件的第一行):51Testing软件测试网fTkjl%Z
       #!/bin/sh51Testing软件测试网s1}@$? j+["l_U[
    符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。  当编辑好脚本时,如果要执行该脚本,还必须使其可执行。51Testing软件测试网 [ D5W!C[,b&bJ\tU
    要使脚本可执行:   编译 chmod +x filename 这样才能用./filename 来运行51Testing软件测试网[!r%S c!{'In
1.1.2 注释
V4E/d*_)Dk*N ZM#X0E0  在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。51Testing软件测试网?V/rFJ
1.1.3 变量
4c_6\ {0jxA0  在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写:51Testing软件测试网ox2ZQ4VB dU$v ?
        #!/bin/sh
%t4ox%vTFz0        #对变量赋值:51Testing软件测试网 Xo3WrN
        a="hello world"
~~p(D8@0        # 现在打印变量a的内容:
4d/bS8y0JTd4P(S8i0        echo "A is:"51Testing软件测试网1jr;eg,^K)h]
        echo $a51Testing软件测试网6M^ a T8G!@
       有时候变量名很容易与其他文字混淆,比如:51Testing软件测试网!u.Yn6x-N6V
        num=251Testing软件测试网~)E7OM$| K)K
        echo "this is the $numnd"51Testing软件测试网0g2rs f:O3V LF }5AZ e9i3V
       这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:
'{(c;q\wp }k0        num=2
+[H/kE-u3M:vTO0        echo "this is the ${num}nd"
ND/Qt UCV'\$\X0        这将打印: this is the 2nd51Testing软件测试网9_}"Mo?t w#CJ4H
1.1.4 环境变量
E&[1v3C}T8~ H#b0       由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录
nVa J:l5w({0脚本中使用环境变量。51Testing软件测试网 {NKlGa{
1.1.5 Shell命令和流程控制
g Y X)H5w5}"{I0       在shell脚本中可以使用三类命令:51Testing软件测试网3D1rEFb{
       1)Unix 命令:51Testing软件测试网@U$GN+pW6_+K
      虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来进行文件和文字操作的。51Testing软件测试网;FyC0z#tUt$tZ4|*O
        常用命令语法及功能51Testing软件测试网~|dVDbv
  echo "some text": 将文字内容打印在屏幕上
iV@x G0[[hsl0  ls: 文件列表51Testing软件测试网3Dr MU$Ceu-w
  wc –l filewc -w filewc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数
"Z/h O)O.x0  cp sourcefile destfile: 文件拷贝
;^YL x)^z0  mv oldname newname : 重命名文件或移动文件51Testing软件测试网:{ R2v;E#B x8`r
  rm file: 删除文件
$k%VtyGk0  grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt51Testing软件测试网^ X*_PF
  cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,这是两个完全不同的命令
0U;n @:H9A5G)B4Y)eR$c0  cat file.txt: 输出文件内容到标准输出设备(屏幕)上51Testing软件测试网1uy'p C&X9C T
  file somefile: 得到文件类型
/h6C*~qwBM&]@0  read var: 提示用户输入,并将输入赋值给变量51Testing软件测试网 eg[;tCrW2z
  sort file.txt: 对file.txt文件中的行进行排序
ky1Uq4GR8@u0  uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq51Testing软件测试网8u A3k9}/Q
  expr: 进行数学运算Example: add 2 and 3expr 2 "+" 3
7G0t2M8|!i5~0  find: 搜索文件比如:根据文件名搜索find . -name filename -print
Ef2}?N2[iqz0  tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile
@Ss$DPE0  basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux51Testing软件测试网 B1eM,pA1R4|
  dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin
L#BW`D:Hn0  head file: 打印文本文件开头几行51Testing软件测试网zwp#a9T H:X3V7Il.K
  tail file : 打印文本文件末尾几行51Testing软件测试网5hPrR,txO:G
  sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。 不要和shell中的通配符相混淆。比如:将linuxfocus 替换为LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
^T2s o8O0  awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。
(BCDre#f Hx0cat file.txt | awk -F, '{print $1 "," $3 }'这里我们使用,作为字段分割符,同时打印第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA
b n)jS(Wey0        命令输出结果为:Adam Bor, IndiaKerry Miller, USA
n|&f~-Z't/`bx0        2) 概念: 管道, 重定向和 backtick
:\ F[4c m;C[Us5U0  这些不是系统命令,但是他们真的很重要。
XQpaC0  管道 (|) 将一个命令的输出作为另外一个命令的输入。51Testing软件测试网 UJKCOOC,PP&b4Z4q
                 grep "hello" file.txt | wc -l
M'd)f*~Q MF0  在file.txt中搜索包含有”hello”的行并计算其行数。51Testing软件测试网#_:|[z8?0Kj"a p }/k
  在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。
`}]jcr+GOW XJ0  重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。
4?Wh@}!O)O] J\0      > 写入文件并覆盖旧文件51Testing软件测试网(gg#[oC jx
      >> 加到文件的尾部,保留旧文件内容。51Testing软件测试网 T9W@/W([t
        反短斜线51Testing软件测试网2K ZKV5Q wl
     使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。
3N]-O Ak~B8A$f0         命令:
W}"S'`qo1O0           find . -mtime -1 -type f -print
{0a w7TV|!n2wf!I0     用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您想将所有查找到的文件打一个包,则可以使用以下脚本:
x;z7R6ph:h4D?0             #!/bin/sh51Testing软件测试网3e4L'QA'oK
             # The ticks are backticks (`) not normal quotes ('):
0S;|9^4n&V1F2nZ7}!t0              tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`51Testing软件测试网G*N'Ge:rD z
       3) 流程控制51Testing软件测试网o6T.E&u9H&c
        1.if51Testing软件测试网U._Y2K W:~IM
    "if" 表达式 如果条件为真则执行then后面的部分:
3Z @9akhM0            if ....; then51Testing软件测试网0IA)e_%J*b?
           ....
|z"E-C3Z,?psK0A0           elif ....; then
&[g\ P3E oe,S(DG0           ....
B1F2BM.`(W0           else51Testing软件测试网&c%jVDG_G;zJ
           ....
b8c3elFIp0           fi51Testing软件测试网2Q-Wl KW.G/Eh
           大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等…
[]$t b}:^.Mpq9p}b0    通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。51Testing软件测试网+Z6kv8V,ML|1@ xi
                 [ -f "somefile" ] :判断是否是一个文件
(Ael*QC0                 [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
_k8^\G.`2U3X0                 [ -n "$var" ] :判断$var变量是否有值51Testing软件测试网Gi,NI7K/Ad"o z
                 [ "$a" = "$b" ] :判断$a和$b是否相等51Testing软件测试网y'N/w*AR
    执行man test可以查看所有测试表达式可以比较和判断的类型。51Testing软件测试网:DaU_[Y
   直接执行以下脚本:51Testing软件测试网 @s8@.ex'BzaD
               #!/bin/sh51Testing软件测试网m(XZ:]u^m"^
               if [ "$SHELL" = "/bin/bash" ]; then
a I@4}I!B \0                    echo "your login shell is the bash (bourne again shell)"51Testing软件测试网i:Oc3S GK
               else
n'];gw:Pl5uO0                    echo "your login shell is not bash but $SHELL"
yBia@~({;]#_%?s0               fi
Ij,[%H K Gw0   变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。
W D&htZy8Z$^0        
$}$}w3wSFQWY0        快捷操作符
Uhh%h}{0        熟悉C语言的朋友可能会很喜欢下面的表达式:
P5q1I N;V#f1c0                  [ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"51Testing软件测试网*Z[|;CtX
  这里 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在则打印” This computer uses shadow passwors”。同样或操作(||)在shell编程中也是可用的。这里有个例子:
/l)R,I$Pu0                 #!/bin/sh51Testing软件测试网)R.tR2]t,G%L?u
                 mailfolder=/var/spool/mail/james
p2u z-|7j&|z0                 [ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" ; exit 1; }51Testing软件测试网_b'Br0}2`D#z
                 echo "$mailfolder has mail from:"51Testing软件测试网*B'i7ra L-x"t
                 grep "^From " $mailfolder51Testing软件测试网|^ e@tb7z [t g&V
        该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令:51Testing软件测试网 g3sA:U0m
  -打印错误信息51Testing软件测试网z:Zp)hkr B7aJ
  -退出程序
7Z|*U9YDy0  我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。
X%RSkV`8WRL0  不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。51Testing软件测试网X C!~ aoJ:g#fb
51Testing软件测试网{!g~/EnG
         2.case
n U`4z-i z2`"O]0               case :表达式可以用来匹配一个给定的字符串,而不是数字。
5n0jTP;S"n4B,n0                      case ... in51Testing软件测试网 ig+T^5yT
                            ...) do something here ;;
d.rpj:wO5H"p0                      esac
fF3m.V"n9V)ejj"C0         让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:
VuF K l2bi5i0                     file lf.gz
s|.PgB n0                   这将返回:51Testing软件测试网9\2bq7`n)r
                         lf.gz: gzip compressed data, deflated, original filename,
T Qc;S.A3UkMc0                         last modified: Mon Aug 27 23:09:18 2001, os: Unix51Testing软件测试网5^ mXaV!S e
             我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件:
9y`#ODd+z4J9v+Z8G H0               #!/bin/sh51Testing软件测试网&HRp(I![o-aQf9X
               ftype=`file "$1"`51Testing软件测试网'iCv qi_
               case "$ftype" in51Testing软件测试网h$g.{6xDA
                       "$1: Zip archive"*)
_F/z^+By0                  unzip "$1" ;;51Testing软件测试网;g{Wv,T+d^
                         "$1: gzip compressed"*)51Testing软件测试网B4B1E7tx0QG|
                    gunzip "$1" ;;
2M*R,R%W7Ew:|0                          "$1: bzip2 compressed"*)51Testing软件测试网J9y6rd~~:}f-AX q
                     bunzip2 "$1" ;;51Testing软件测试网2Y4g-zy[,Qs
                           *) echo "File $1 can not be uncompressed with smartzip";;
.Rb^c9B0                esac
*|3T8L)]#Lg-F ]0fo0         您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。51Testing软件测试网,E|9[.]%T*Mk
也就是说,当我们运行:
A1k wg8\0                    smartzip articles.zip51Testing软件测试网#GF pY T%T`Y7\HG"L
                    $1 就是字符串 articles.zip
G)]#s} dT0                3. selsect51Testing软件测试网iI@+ZvZ!^
                  select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。
)R yo2a S k2{0                    select var in ... ; do51Testing软件测试网I8BU D9n,d
                         break51Testing软件测试网)k6~4~3OmK?r:`
                            done
|G$C?5o&k;F0                            .... now $ var can be used ....51Testing软件测试网6CET+|r-w Cc*l ?
                   下面是一个例子:
RB-~L/Jn4z5]A0                         #!/bin/sh51Testing软件测试网!U&\*L{mK0jt
                         echo "What is your favourite OS?"
C#[mD QeA#L5|0                         select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do51Testing软件测试网?gu S;b-{Xo4k KJ }
                    break51Testing软件测试网2Nh;Z MmQ[w
                                done51Testing软件测试网DE$I v{2A3Z
                           echo "You have selected $var"51Testing软件测试网E CYp~4m,r)e
              下面是该脚本运行的结果:51Testing软件测试网R-Dvekg;C
                               What is your favourite OS?51Testing软件测试网 l3{.GX/sy5B$a!e2Z@
                                    1) Linux51Testing软件测试网\0U;l;y:Bg;S2N$f/N{
                                    2) Gnu Hurd51Testing软件测试网%?1t0hy,`0yOc
                                    3) Free BSD
q1Ij~!a0                                    4) Other
|&Qr'^(_'[6DG0                                  #? 1
_ZB;g*VY0                                You have selected Linux
v{6qI mkMEK'}0         注:var是个变量,可以换成其它的值。break用来跳出循环,如果没有break则一直循环下去。done与select对应。51Testing软件测试网7tao|)NtPt Lb
                  4.loop
%Hhho o5}/_9SH0                      loop表达式:51Testing软件测试网FGlGp9s
                            while ...; do
_(Mx!Q jj#|ro"E`0                                      ....51Testing软件测试网a4Z]JN8|!O!J
                               done
[j6?.Wl1S.l0             while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true.
,K W;Xz&wP(I0关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。51Testing软件测试网$W)E^mN*f1O
  51Testing软件测试网xl7mZ3O1j `il
                     for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量:
T?1[/R fb0                          1,   for var in ....; do
v)r8\Bp(Lo0                                 ....
i"H$W X~,~0                                done51Testing软件测试网on i3Mk5e P'j
                       在下面的例子中,将分别打印ABC到屏幕上:51Testing软件测试网,ZEb,QI Je
                            #!/bin/sh
Oy`#pBL!d*a0                                    for var in A B C ; do
Nw$a*?c su/[)I0                                 echo "var is $var"51Testing软件测试网n(|:l2S_4vt
                                     done51Testing软件测试网j(R"@#jM
51Testing软件测试网y:^0U,k3]ij
                           2,   for (( 条件一; 条件二; 条件三 );do
J+s ku|XM8Na0                                ...51Testing软件测试网'e0wn7b8lM L!P
                                done51Testing软件测试网!CZIc,_"h7gu!n
                        例:51Testing软件测试网.}h7Ox$M\
                     
N#D b^ C0                   for ((i=1;i<10;i=$[$i+1]));do
pc J{SmuY0
n4a0w`uRP0                             echo "a"
s`'C i Q nB0                          done
S"v)X+]7Q:PN{0输出:51Testing软件测试网$@&VB*jD/ys'aa D#G(m
51Testing软件测试网8i]NmP
a51Testing软件测试网;ZJ%nN!a~$C g` H
a51Testing软件测试网1c!xL,e_2E t9H
a
zc'xH:s F#T0a51Testing软件测试网\;c{y'U_,`2QE6x r
a51Testing软件测试网LfDW{(d B B
a51Testing软件测试网8[m5P-~o0@
a51Testing软件测试网{M']2k9EsGKnv
a51Testing软件测试网 G K9\+w@w;S
a
9y$]#_Z4S n/YZE051Testing软件测试网l\~&{'bn'\S
条件一:这可以看成是『初始值』,如上面的例子中,初始值是 i=1 啦!
8K _x!F-s3z%m:w/h]0条件二:这可以看成是『符合值』,如上面的例子中,当 i<=100 的时候都是符合条件的!51Testing软件测试网*g7?`+BO*j,`?%Oc
条件三:这可以看成是『步阶』!也就是说, i 每次都加一! 所以啦!上面的例子是说:由 i=1 开始到 i<= 100 ,每次 i 都加一来执行底下的程序段(就是 s=s+i ),当 i >100 (也就是 i=101 )就跳出这一段程序段!怎样!不难吧!
C%o1u!ve4b0fCmz s`051Testing软件测试网3T(Ee1A ?U.a F t
51Testing软件测试网DSQ3Ku y8F+|
51Testing软件测试网 G1s7Odk^pm&k
51Testing软件测试网|0C,a:V;UO]t M
                        下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:51Testing软件测试网4u ?+CWI7d3N#K-@
                          #!/bin/sh51Testing软件测试网 w\*K u*s Q
                          # list a content summary of a number of RPM packages51Testing软件测试网W]qV7t)j b-y [
                          # USAGE: showrpm rpmfile1 rpmfile2 ...
]&^GO{:d0                          # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm51Testing软件测试网i0q6J(M W+S,MX
                            for rpmpackage in $*; do51Testing软件测试网wtR&A'o
                         if [ -r "$rpmpackage" ];then51Testing软件测试网fkca;KK9o H-}
                         echo "=============== $rpmpackage =============="
]R h2Gn5u |%\#O0                          rpm -qi -p $rpmpackage
exCn [ C i0f k0                          else
4}0y ^o.\0                           echo "ERROR: cannot read file $rpmpackage"51Testing软件测试网4N+EM} Bm1LZ0C\aGp
                         fi
/DTNJL oK0VT0                              done51Testing软件测试网Z$R1qH [y]
                   这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。51Testing软件测试网H!G(Qq"E4]? a5^
                        如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm
,IE!yKD7jJ0                                   此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.
|E9GFL;xx'UIxG051Testing软件测试网 N9ZX2iX)[-V
51Testing软件测试网3?JF@(n_pM7k

`R^ {7E:I9t+s;} S0『until:直到条件相同的时候才离开程序』;51Testing软件测试网_{;A(K?/\._2@
『while:当条件相同的时候,就继续做!』  51Testing软件测试网$xK:AxtZ/N
51Testing软件测试网8q2gb"A!Ze#ccQ
until [ condition1 ] && { || } [ condition2 ] ...51Testing软件测试网3b.\"R Mic

({1]7Oz6v051Testing软件测试网:iV(\ aHD&}

fd$~l,`I[&^9QY0
f)Ip`#w0                 5. 引号51Testing软件测试网uo#VW2a9qh.F
                   在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符(比如*)替换成合适的文件名,它变量替换成变量值。为了防 止程序作这种替换,您可以使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件, mail.jpg 和tux.jpg。51Testing软件测试网4V3\/p+dI8r?%B;Y
          编译SHELL脚本51Testing软件测试网 S B? a)t9d
          #ch#!/bin/sh mod +x filename51Testing软件测试网+^k EJ!?t
 cho *.jpg       ./filename 来执行您的脚本。
/i(a:~*L:@,b0  这将打印出"mail.jpg tux.jpg"的结果。
R4g)TL2bUW0    引号 (单引号和双引号) 将防止这种通配符扩展:51Testing软件测试网S-k)E:}#z'?2J
             #!/bin/sh
?I/[uD:old s0             echo "*.jpg"
o[KEiH(e0             echo '*.jpg'51Testing软件测试网(@QF+k)eT e
  这将打印"*.jpg" 两次。51Testing软件测试网6r[N1nQ9u"jb/G
  单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。
?b2?7pr H7o*s0         #!/bin/sh
a CJ/l&D(o0         echo $SHELL
'[(^:\ ^'Z]J)B0         echo "$SHELL"51Testing软件测试网9~IXh%I(z
         echo '$SHELL'
ks6b9],pSh0   运行结果为:
v1K$MMT,U;E#Y0             /bin/bash51Testing软件测试网1q,D,@\#]-s o5V7P
             /bin/bash51Testing软件测试网k Tz/Y#s:J
             $SHELL51Testing软件测试网6TR)A0g)}K`W%x8N
  最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:51Testing软件测试网'xX \,XQ
           echo *.jpg
6SC2`o0I&R%{!n0           echo $SHELL
jBD|'~!?1H2U1f^o|0  这将输出:
,| Gy `5r:g0           *.jpg51Testing软件测试网 O `LoG
           $SHELL
9Zs [BY7v!i0z0         6. Here documents51Testing软件测试网+y KGQ*agF2t~$R
          当要将几行文字传递给一个命令时,here documents(译者注:目前还没有见到过对该词适合的翻译)一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents就不必用echo函数一行行输出。 一个 "Here document" 以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:
#@O+e A[p[0         #!/bin/sh51Testing软件测试网*uHc]W,a ?
         # we have less than 3 arguments. Print the help text:51Testing软件测试网O{[F+y`0AMx5E
            if [ $# -lt 3 ] ; then
E O0Kcy'p%C8a0                 cat <
*Z-A8s2D{0Ef| O0                 ren -- renames a number of files using sed regular expressions
%F_${g$P6H3?/kc0                 USAGE: ren 'regexp' 'replacement' files...
U_b|tX!i4b#p.i0                 EXAMPLE: rename all *.HTM files in *.html:51Testing软件测试网5HM8H}5L(@6x.I
              ren 'HTM$' 'html' *.HTM
4^C:Q| HbaFGR_[0                 HELP
hv[Y j\ C5I0              exit 0
I OKJ8y0            fi51Testing软件测试网hYGn9vG(O
            OLD="$1"
zm[.`7x(HBw6F a0            NEW="$2"
'G9ZmY p+v tBil0          # The shift command removes one argument from the list of51Testing软件测试网:I{I2d5i
          # command line arguments.51Testing软件测试网0qK']wg m7K
          shift51Testing软件测试网Y$@sEj U HI(o
          shift51Testing软件测试网i*}'v/a+^j
          # $* contains now all the files:51Testing软件测试网oylRt
         for file in $*; do51Testing软件测试网f]#{/Ucy`3{v
          if [ -f "$file" ] ; then51Testing软件测试网"n8R`~|W
             newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`51Testing软件测试网Ga/K#v3T1pxl
             if [ -f "$newfile" ]; then
kK8gj;R,h0ao0                  echo "ERROR: $newfile exists already"
L7Z0`b XN0             else51Testing软件测试网/n2Y#Y[gy"H8U
                  echo "renaming $file to $newfile ..."51Testing软件测试网0Mu#vtxD$p
                  mv "$file" "$newfile"51Testing软件测试网;t.Dh\ Qz2Y A'w,q [
              fi
ig TT.d4H)O%c{0            fi51Testing软件测试网0} O Z,]C
           done51Testing软件测试网X#o^cA
        这是一个复杂一些的例子。让我们详细讨论一下。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。 如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从 参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我 们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目 的:得到了旧文件名和新51Testing软件测试网 L4?#z'Ngj%{)e
文件名。然后使用mv命令进行重命名。51Testing软件测试网Z5ZBs![#c
          4)函数
*Q1M:ix&HZXg"T%le0             如果您写了一些稍微复杂一些的程序,您就会发现在程序中可能在几个地方使用了相同的代码,并且您也会发现,如果我们使用了函数,会方便很多。一个函数是这个样子的:51Testing软件测试网{dqk,P,g%R4bF
          functionname()51Testing软件测试网3[S D6FuZ(U,RS
          {
4|3l?oGl0                 # inside the body $1 is the first argument given to the function51Testing软件测试网c d'g ``
                 # $2 the second ...
;wbT0H&uvL+F-e0                             body51Testing软件测试网-oH!A#N z"@#j O
            }51Testing软件测试网rd2z:W_KS%p,Q
          您需要在每个程序的开始对函数进行声明。51Testing软件测试网 Cm Jr q {,c&U
   下面是一个叫做xtitlebar的脚本,使用这个脚本您可以改变终端窗口的名称。51Testing软件测试网(iE*sp OQR|%m*r
           这里使用了一个叫做help的函数。正如您可以看到的那样,这个定义的函数被使用了两次。
4k |P-\)\A0               #!/bin/sh51Testing软件测试网vwz-}ui&|;q ZP3f
               # vim: set sw=4 ts=4 et:51Testing软件测试网 QJ(Z(fB6HA:D
               help()51Testing软件测试网FeZ0eeH
               {51Testing软件测试网7fW/IiO jB(ve
              cat <51Testing软件测试网X8`3~RQ s,O
                     xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
jz d u/x4C;MQ%g"e0                     USAGE: xtitlebar [-h] "string_for_titelbar"
e7h.P6fTB\0                      OPTIONS: -h help text
,t"{I"j&[f|9?0                     EXAMPLE: xtitlebar "cvs"51Testing软件测试网qx0_#K3i4g;F]:{
                     HELP51Testing软件测试网#PU.JZIC;Q6[4mv.Q
             exit 051Testing软件测试网k7A(G#v!t p6U
               }51Testing软件测试网(bNn M P fR6o
               # in case of error or if -h is given we call the function help:51Testing软件测试网8N;K9TjOh3~"D0n4q,P
               [ -z "$1" ] && help51Testing软件测试网"Kt.U b`m P3hh|
               [ "$1" = "-h" ] && help51Testing软件测试网9LEs8ZU2g2W
               # send the escape sequence to change the xterm titelbar:51Testing软件测试网QR/veuG~v/x
                 echo -e "33]0;$107"51Testing软件测试网 sh(TH o#ox8v
                #
YPSh'FMoF pV/U"Q0            在脚本中提供帮助是一种很好的编程习惯,这样方便其他用户(和您)使用和理解脚本。51Testing软件测试网9ps&C3n+B L,l5u
        命令行参数
Ki}6LI0  我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。 但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (比如文件名)。有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无遗是一个不错的方法。
R&RW#{jM^^0         #!/bin/sh51Testing软件测试网 iX;BK:t+l E
         help()
@J0P;JM0         {51Testing软件测试网R#@_I-_pXU
            cat <51Testing软件测试网4B,d(WV#C
               This is a generic command line parser demo.51Testing软件测试网9g(h)\b"j P0P
               USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2
5rO9v]#{B4}d0               HELP
3qF_7}P+R1l0            exit 051Testing软件测试网6r'^;h9e)q([ x)p;?Fa:]
         }
+j.Gq I5z8^ X0          while [ -n "$1" ]; do51Testing软件测试网5U+{(Nz;f(H&h-L(_
        case $1 in51Testing软件测试网io9@7J`2_
       -h) help;shift 1;; # function help is called51Testing软件测试网@ j }^i.pa;e5h t.p
       -f) opt_f=1;shift 1;; # variable opt_f is set51Testing软件测试网&`5P2]-hXN"yO5q
        -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
P@&P!b#K0        --) shift;break;; # end of options51Testing软件测试网0{I!l6c?I4Sw
       -*) echo "error: no such option $1. -h for help";exit 1;;
1z};G7e7XJa Cq0       *) break;;51Testing软件测试网1`4d\5C zI
          esac51Testing软件测试网SC,P b"F^w
          done
cyGi$wY%\&M B_0          echo "opt_f is $opt_f"
7N7f(Z#^6lrv$v/|0          echo "opt_l is $opt_l"51Testing软件测试网QMR(x.MTD8q C
          echo "first arg is $1"
w,cH5l!S0          echo "2nd arg is $2"51Testing软件测试网:Snh;f:c%Lk([0zZ)Q
  您可以这样运行该脚本:51Testing软件测试网;Hvy5H.YfF+C
                 cmdparser -l hello -f -- -somefile1 somefile251Testing软件测试网 A+bc(]n(Il/M4@$y
  返回的结果是:
+I"Oa D5L+B0             opt_f is 1
:U w-T-{"UZ#s3wP,A"o0             opt_l is hello51Testing软件测试网ew;P`?+^9X
             first arg is -somefile151Testing软件测试网LU3e*k D_?&r)H
             2nd arg is somefile2
| tvX/fc#A _{J!T%J0  这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数.
)@;ae`;P@ [ Fly051Testing软件测试网p,VO"}Vv:ol
51Testing软件测试网H ]&{ ng Vd~u#K7L
第2部分 实例51Testing软件测试网*~c/x4{H5XPu*K!M
51Testing软件测试网/?,F/EEw)E^d~M
    现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下copy命令:51Testing软件测试网-I7DXo8^ P,Ms
cp framework.sh myscript.
P5f:Ru-P3VX0 然后再插入自己的函数。
Hb5J-o'zqb2rF0  让我们再看两个例子:
4M u T6QGO'\!S0  二进制到十进制的转换51Testing软件测试网@"ME[8{-@}K-B
  脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:51Testing软件测试网 R,QC{4E4n"r
#!/bin/sh51Testing软件测试网d0Y tPL7B"MVV
# vim: set sw=4 ts=4 et:51Testing软件测试网(A`AB C
help()51Testing软件测试网D}T7` W
{
2h.Ra3wO!t1t0 cat <
1RF K7P8Za;` {C0b2h -- convert binary to decimal51Testing软件测试网L,R'Tb6h ~!U
USAGE: b2h [-h] binarynum51Testing软件测试网q g$X'U6py2Y4?
OPTIONS: -h help text
CkU9gYn#e0EXAMPLE: b2h 11101051Testing软件测试网1T0l}J S2y:aT+_l
will return 5851Testing软件测试网` W/c~'oC:I
HELP
X\ x_0?yqAH0 exit 0
*eq1a$z7y V0}
Q @4F,m\*r\(~b M0error()51Testing软件测试网-U IvI)I2Uz
{51Testing软件测试网 S~{EN!C'rt
  # print an error and exit51Testing软件测试网?HH'C]
  echo "$1"51Testing软件测试网{_t5c+HL u(fhOB
  exit 1
e`X},?"E0}51Testing软件测试网T'l8mi2O
lastchar()
Mc6arut0r0{51Testing软件测试网/i@ lgVq:e
  # return the last character of a string in $rval51Testing软件测试网ey1nu9~
  if [ -z "$1" ]; then51Testing软件测试网 Z|B+{*v4S+fk
    # empty string51Testing软件测试网|DR&X w3T
    rval=""51Testing软件测试网kdce&M
    return51Testing软件测试网.C1@x.y I{Ck
  fi
}J R Q'S0  # wc puts some space behind the output this is why we need sed:
G7|n%L)k i5Z(W0  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
$h%{ r9S'ax0  # now cut out the last char51Testing软件测试网t:NN8b#n8| F'~f[
  rval=`echo -n "$1" | cut -b $numofchar`
E4y0H*bK;P0}51Testing软件测试网7t?#V.uDU+X%w
chop()51Testing软件测试网;i6NsRe_Wl
{
3d+Q5j7|vy[#G*As0  # remove the last character in string and return it in $rval
Ps5rbV!U0  if [ -z "$1" ]; then
sg+o.Y7E/F0    # empty string51Testing软件测试网&L[cOl-O,UGn
    rval=""51Testing软件测试网/II1Fwy;K
    return51Testing软件测试网k oFmR"eLek
  fi51Testing软件测试网!J#Vd EhyIK
  # wc puts some space behind the output this is why we need sed:
0Ne&HLu*gU.~/T-d0  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `51Testing软件测试网`8~ z:INo {a&Kn?
  if [ "$numofchar" = "1" ]; then51Testing软件测试网O]R6i7pC
    # only one char in string
H+^V8s t/[ _0    rval=""
u%IA%O$`B0    return51Testing软件测试网#g\X7H0{M`:c
  fi51Testing软件测试网Oy9j7^:WN$Dd
  numofcharminus1=`expr $numofchar "-" 1`51Testing软件测试网8A W v+M!?@,ql1NS
  # now cut all but the last char:
Sf Jf5mph0  rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`51Testing软件测试网4Y-d_^3m#H^@*G
}
^~.Yg;H/H6ei$M/u^0while [ -n "$1" ]; do
F0d&BV"L4p z0case $1 in51Testing软件测试网8NU4vrz$nG
  -h) help;shift 1;; # function help is called
Q1iw/X]{0  --) shift;break;; # end of options51Testing软件测试网MN`7S)z Ot!u#x M
  -*) error "error: no such option $1. -h for help";;51Testing软件测试网~AO6VP `m
  *) break;;51Testing软件测试网2XO0aJS:ih
esac
gD8M%f+|@K0done51Testing软件测试网5Zn0Je)w
# The main program
9d&l@D-Cf(e:A0U0sum=051Testing软件测试网NFE*p;{jd
weight=151Testing软件测试网I9~)gW%Oh.^
# one arg must be given:
p.^{'N:o7oHg0[ -z "$1" ] && help
\ E-OUA{l$Ti0binnum="$1"
wY:k'm Eu[T_0binnumorig="$1"
nQ7U6lp+O.Y$P[0while [ -n "$binnum" ]; do
b*Y l|4V_C0  lastchar "$binnum"
oRM0y6^f0  if [ "$rval" = "1" ]; then
$t4].\"q5IR^ O0    sum=`expr "$weight" "+" "$sum"`51Testing软件测试网,wV`,C?/C3Y
  fi
5RmHu:|nCR s/n0  # remove the last position in $binnum51Testing软件测试网 u!g7jhgg6hp
  chop "$binnum"51Testing软件测试网 x.ech,LZdy
  binnum="$rval"51Testing软件测试网1JQ2?_a6p,w%Ob(c
  weight=`expr "$weight" "*" 2`
'~z#t u~wR?3}n/R5h0done51Testing软件测试网e!R.oo)am8OFv
echo "binary $binnumorig is decimal $sum"51Testing软件测试网%BQ*Fv9H e#F4Z
   该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制:
RJ9`;X(o#_Pn00 * 1 + 1 * 2 = 2
Hl!\O_0  为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字符。
kS;uW)y4W(j;|+y#a0    文件循环程序51Testing软件测试网;L6fXS2TV
  或许您是想将所有发出的邮件保存到一个文件中的人们中的一员,但是在过了几个月以后,这个文件可能会变得很大以至于使对该文件的访问速度变慢。下面的 脚本rotatefile可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1,而对于outmail.1就 变成了outmail.2 等等等等...
U5XLq](H.y%G3K0#!/bin/sh51Testing软件测试网 G-Q KN9R0n
# vim: set sw=4 ts=4 et:51Testing软件测试网i7|@g9`9z7Gy|
ver="0.1"51Testing软件测试网:Y4T R*|[u
help()51Testing软件测试网 |&z4htF8r_2b8\e
{
`}}n0l+G+Q0  cat <
Jj O*ys-wK#o0rotatefile -- rotate the file name
0d xj.hW{#|g2O0USAGE: rotatefile [-h] filename
7Ivn @?o `0cWm0OPTIONS: -h help text
"s}+uN5[.X!d0EXAMPLE: rotatefile out51Testing软件测试网,L ~h0?$fta3n??
This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1
I FT%o;ZM$D%Os0and create an empty out-file51Testing软件测试网`:R)o4UT)`f/Z
The max number is 10
Fo#oL MZL ~0version $ver
WO~%R \a9aL0HELP51Testing软件测试网;W~ ^ Yvd6k2P5~-s
  exit 0
_(t'E2p'M/?(^{T}0}51Testing软件测试网.g!]7Wh#p"gCv_;e
error()
fS+o)[b0{
o@Ik0[0  echo "$1"
cf9N O%\QeD'lNg0  exit 151Testing软件测试网k2k#J;[XN7|yT F
}
s%J!i)W P9j3u_0while [ -n "$1" ]; do
5c+W-Dw*B0case $1 in
4KX$v}^$aA/}0  -h) help;shift 1;;
3Nq?&x)v8Ui0  --) break;;51Testing软件测试网(^eQ&a0om
  -*) echo "error: no such option $1. -h for help";exit 1;;51Testing软件测试网l$T8~6I/DL:~6T
  *) break;;51Testing软件测试网oH/u8Y9q
esac51Testing软件测试网!~bVc Y(p
done51Testing软件测试网JX*nps
# input check:
)i X.~BQ0if [ -z "$1" ] ; then
$dv.},`l3F0error "ERROR: you must specify a file, use -h for help"51Testing软件测试网Bk+p&o/uCXcb
fi51Testing软件测试网cjJ dWj%M!\
filen="$1"51Testing软件测试网^6@,l"K l_
# rename any .1 , .2 etc file:
A0a$M0ox,V0for n in 9 8 7 6 5 4 3 2 1; do51Testing软件测试网-c#JB"?8P*Y:` f!Y,r
  if [ -f "$filen.$n" ]; then51Testing软件测试网8OM/hn-v
    p=`expr $n + 1`
f `pn }+? QG0    echo "mv $filen.$n $filen.$p"51Testing软件测试网eND(?m S1kt1W ~8V
    mv $filen.$n $filen.$p51Testing软件测试网#{.gv6["Z'I,c
  fi51Testing软件测试网 T'y&y"jX hv
done
/s5[8Y lc'E'c2mI9U0# rename the original file:51Testing软件测试网jD ]8|iO:~
if [ -f "$filen" ]; then
Sjs7k-q v-p?(e0  echo "mv $filen $filen.1"
2_tq I&t9d-u ktM6E0  mv $filen $filen.1
v4L$X4Gd+eX[~0fi51Testing软件测试网6VqrW1B So
echo touch $filen51Testing软件测试网9zY2e @nn
touch $filen
(JesM(R!R+SR%l0  这个脚本是如何工作的呢?在检测用户提供了一个文件名以后,我们进行一个9到1的循环。文件9被命名为10,文件8重命名为9等等。循环完成之后,我们将原始文件命名为文件1同时建立一个与原始文件同名的空文件。51Testing软件测试网G yi)Q8FRL
调试51Testing软件测试网@vcQ v$e;?.]y
  最简单的调试命令当然是使用echo命令。您可以使用echo在任何怀疑出错的地方打印任何变量值。这也是绝大多数的shell程序员要花费80%的时间来调试程序的原因。Shell程序的好处在于不需要重新编译,插入一个echo命令也不需要多少时间。
!oU[[;p]:`-Fc0  shell也有一个真实的调试模式。如果在脚本"strangescript" 中有错误,您可以这样来进行调试:51Testing软件测试网:t"qB|[z3i
sh -x strangescript.
rI+@,k'N7w0  这将执行该脚本并显示所有变量的值。51Testing软件测试网Y @TE'Y
  shell还有一个不需要执行脚本只是检查语法的模式。可以这样使用:51Testing软件测试网*BcQ!v~A5a6S
sh -n your_script.
O*jJcWp _i0  这将返回所有语法错误。51Testing软件测试网f+_8\-\t0nZ

TAG:

引用 删除 liaomin545   /   2011-09-14 14:25:05
-1
Colorful days 引用 删除 ivwseeqg   /   2011-08-17 09:45:22
5
 

评分:0

我来说两句

Open Toolbar