脑袋里装的浆糊咩?总是记不住,总是做不对。。。。要说你多少次???

存档:必须掌握的shell编程

上一篇 / 下一篇  2010-07-20 20:21:01 / 个人分类:他山之石

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

Linux Shell在线模拟器
http://www.masswerk.at/jsuix/index.html

一个在网页上的linux shell模拟器,是可以为那些不熟悉linux 的人们在Microsoft Win环境下练习linux 的一个工具。既不耽误学习,也不耽误正常的工作,哈。


E w+^Ipl16573151Testing软件测试网x6g3rq'Z$E
1.Linux脚本编写基础
^1T0CO^_;i1657311.1 语法基本介绍51Testing软件测试网)S4lk a*z YI'b9X/X
1.1.1 开头51Testing软件测试网 |5}^$ws:i;Im y
       程序必须以下面的行开始(必须放在文件的第一行):51Testing软件测试网](J:a&c j,qH
       #!/bin/sh
ncC S[u*y5`-O W165731    符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。  当编辑好脚本时,如果要执行该脚本,还必须使其可执行。
?WJZ"Q8Y?~165731    要使脚本可执行:   编译 chmod +x filename 这样才能用./filename 来运行51Testing软件测试网 UB%tl-c2H)V"k
1.1.2 注释51Testing软件测试网S,N%?RF&N7G b
  在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。51Testing软件测试网"uJP/C:?:vI a6nMsI
1.1.3 变量51Testing软件测试网CB T1H5j r ty
  在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写:
Z7ZD!C%v[Tt `165731        #!/bin/sh51Testing软件测试网-jB#t0P8CJj
        #对变量赋值:51Testing软件测试网D`*z7o,D X/z
        a="hello world"
:]g$K~7Ms;ecU165731        # 现在打印变量a的内容:51Testing软件测试网$jd W;OW
        echo "A is:"51Testing软件测试网2x(r5A d"q [ ~i
        echo $a51Testing软件测试网(ap&| {Z
       有时候变量名很容易与其他文字混淆,比如:
n3gf'|oE#S165731        num=251Testing软件测试网$kfk1AY
        echo "this is the $numnd"
;z3_5|6\En165731       这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:51Testing软件测试网,y!Qs R:H9L/{
        num=251Testing软件测试网CT,^g#y
        echo "this is the ${num}nd"51Testing软件测试网.^ n#P2^;?0q
        这将打印: this is the 2nd51Testing软件测试网8F na^1Rf
1.1.4 环境变量
`|%G3oW#Rx)F165731       由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录51Testing软件测试网 A0f S;D{;d
脚本中使用环境变量。51Testing软件测试网\ BM!s;`@
1.1.5 Shell命令和流程控制
6? kD$c8\-_5j*K+h165731       在shell脚本中可以使用三类命令:51Testing软件测试网z0jr6SIg$m
       1)Unix 命令:
8pDQe }8}BC165731      虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来进行文件和文字操作的。51Testing软件测试网/m|&@M Q;as
        常用命令语法及功能51Testing软件测试网Q l\5e:SS&kw9y-G
  echo "some text": 将文字内容打印在屏幕上51Testing软件测试网9Qb1I k t
  ls: 文件列表51Testing软件测试网x6JQ E_
  wc –l filewc -w filewc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数51Testing软件测试网"E c}+s%QV?ds&T!f
  cp sourcefile destfile: 文件拷贝
-t @:lU6V'K n(j.n165731  mv oldname newname : 重命名文件或移动文件
Fu.nv2^/U8PEi]0p165731  rm file: 删除文件51Testing软件测试网'w5t3c2j+b@ d
  grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt51Testing软件测试网&o8g Ft8R&}o1j
  cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,这是两个完全不同的命令
j5zZ HeH#VdbH165731  cat file.txt: 输出文件内容到标准输出设备(屏幕)上51Testing软件测试网)AtC D@S*ZSy^
  file somefile: 得到文件类型
s b?^Dv O#q1X165731  read var: 提示用户输入,并将输入赋值给变量51Testing软件测试网6`IP8LUk)P#zB
  sort file.txt: 对file.txt文件中的行进行排序51Testing软件测试网)H'U$aX$P+c*R F)WF2T
  uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq51Testing软件测试网!pE0}4u'M|
  expr: 进行数学运算Example: add 2 and 3expr 2 "+" 3
.N3G9j@&q$f.A165731  find: 搜索文件比如:根据文件名搜索find . -name filename -print
"]5Z!}xZ3O \165731  tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile51Testing软件测试网9]R$V)ax}
  basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux
v1zHfI6{)x165731  dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin51Testing软件测试网^G s0cgt)h
  head file: 打印文本文件开头几行
R/xfC3?7`T165731  tail file : 打印文本文件末尾几行
fBvQX2Wvf165731  sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。不要和shell中的通配符相混淆。比如:将linuxfocus 替换为LinuxFocus :cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file
LmFsy1Q165731  awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。51Testing软件测试网]Q5h"p C
cat file.txt | awk -F, '{print $1 "," $3 }'这里我们使用,作为字段分割符,同时打印第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA
+a5{F5@4j"b4cX&|:p165731        命令输出结果为:Adam Bor, IndiaKerry Miller, USA
t]_4| i5}9F165731        2) 概念: 管道, 重定向和 backtick
I&JS2uJ"L0C @165731  这些不是系统命令,但是他们真的很重要。
:jT0prMst!\165731  管道 (|) 将一个命令的输出作为另外一个命令的输入。
Yd w,Z ~ r O165731                 grep "hello" file.txt | wc -l51Testing软件测试网6R G9F#FVMcj P
  在file.txt中搜索包含有”hello”的行并计算其行数。
ng"V o;B4v,o1Xx165731  在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。51Testing软件测试网[Lf]*h;oq
  重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。51Testing软件测试网9N!MH`+Q
      > 写入文件并覆盖旧文件
_+g0`4fH$h:VJ:[1x165731      >> 加到文件的尾部,保留旧文件内容。
)aZ2O:PRG3q165731        反短斜线
1fu8l-DVV+e2TNt165731     使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。
j YN#U\&M165731         命令:
1S4}*k;wg165731           find . -mtime -1 -type f -print51Testing软件测试网.r&qp;Vec)u7x O.AE
     用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您想将所有查找到的文件打一个包,则可以使用以下脚本:
{[k^ P7C S'N!FY165731             #!/bin/sh
x+O0L X%Q1Zp#JG165731             # The ticks are backticks (`) not normal quotes ('):
\@ KL%c$K6vv y/P/X2P165731              tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`51Testing软件测试网(? W\D6h U
       3) 流程控制51Testing软件测试网 TE0ylH\+?-]
        1.if
"N6Lv,i"S[165731    "if" 表达式 如果条件为真则执行then后面的部分:51Testing软件测试网/gB8a2Vn"zH
            if ....; then51Testing软件测试网 v R3U@.C;{6Ml D
           ....51Testing软件测试网un6\:v3kY&o7{!w
           elif ....; then51Testing软件测试网AF%NW5U
           ....51Testing软件测试网k%X}:KZiQ]G1n
           else
QK&r6R?Z165731           ....
jn,cv;j165731           fi51Testing软件测试网wX9P0soF;q
           大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等…51Testing软件测试网9\$nC D7` G
    通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。51Testing软件测试网lxx O/u/Ka
                 [ -f "somefile" ] :判断是否是一个文件51Testing软件测试网4UE0RJ(~0X'|~
                 [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限51Testing软件测试网-j+O,lmT
                 [ -n "$var" ] :判断$var变量是否有值51Testing软件测试网|j$^ Jv(uiX,g
                 [ "$a" = "$b" ] :判断$a和$b是否相等
O-bL!a}"J \165731    执行mantest可以查看所有测试表达式可以比较和判断的类型。
"Xq1JZ'ZU%Ft&GM P W165731   直接执行以下脚本:51Testing软件测试网kK6mE+H2|.vK
               #!/bin/sh
2G*Qs Uc,Epsfc#t165731               if [ "$SHELL" = "/bin/bash" ]; then
v.Q*aCTj165731                    echo "your login shell is the bash (bourne again shell)"51Testing软件测试网B!e^ v\+N e4Qq
               else
!Wjw5o"cym g]6Jm165731                    echo "your login shell is not bash but $SHELL"51Testing软件测试网 g:wc%ECq C2{$X
               fi
Aa1Kx fa L165731   变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。
/QNplQ z$A ]jt165731        51Testing软件测试网!I1g*G zU0?^'cv
        快捷操作符
D0}.f;N D.z!e165731        熟悉C语言的朋友可能会很喜欢下面的表达式:51Testing软件测试网#}^9W}v!D
                  [ -f "/etc/shadow" ] && echo "This computer uses shadow passwors"
j(~{^^s%j165731  这里 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在则打印” This computer uses shadow passwors”。同样或操作(||)在shell编程中也是可用的。这里有个例子:51Testing软件测试网h*V_B8`ko gS)H
                 #!/bin/sh
qGp?TZ9m6p%w?165731                 mailfolder=/var/spool/mail/james
0Q(o%j"~7or165731                 [ -r "$mailfolder" ]' '{ echo "Can not read $mailfolder" ; exit 1; }
9X'^,HY?165731                 echo "$mailfolder has mail from:"
F7fn;vksx v;X165731                 grep "^From " $mailfolder51Testing软件测试网9[&ZcS)VVr+W$^H]$B$W
        该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令:51Testing软件测试网3@%J| G!R U
  -打印错误信息51Testing软件测试网v9w/S t/O.Y6G%?Z
  -退出程序
4j-B*v@9uyO)W165731  我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。51Testing软件测试网x b7Iqm0o(w g
  不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。51Testing软件测试网Mycc+T0@#cla C(}
51Testing软件测试网.Lb[0dZ$_!G
         2.case51Testing软件测试网 UrG5} qS3lv
               case :表达式可以用来匹配一个给定的字符串,而不是数字。
6J!?6H5n:q{9c W(`165731                      case ... in
h h+k0e-J165731                            ...) do something here ;;
m {xQ{/s v P3m165731                      esac
L%n]8K5wwLh}165731         让我们看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如:
&X;[G6P'B165731                     file lf.gz
hp0PS'Un@165731                   这将返回:51Testing软件测试网 d"A&_1I4o
                         lf.gz: gzip compressed data, deflated, original filename,51Testing软件测试网/H-ikt;qJH/I
                         last modified: Mon Aug 27 23:09:18 2001, os: Unix
9G-r0F\L Q a6LUF165731             我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件:51Testing软件测试网4o.Yq4y!Z
               #!/bin/sh
q^_/o/@kJi)i4y165731               ftype=`file "$1"`
;Fo|3Km0hX165731               case "$ftype" in
5[F*x }$C165731                       "$1: Zip archive"*)
T } h&v$e-I"{t165731                  unzip "$1" ;;51Testing软件测试网Z\Iiw$]9Lil3Q!}!O
                         "$1: gzip compressed"*)51Testing软件测试网!Kq$@!R&b6rw}
                    gunzip "$1" ;;51Testing软件测试网o;~2bL}8OS
                          "$1: bzip2 compressed"*)51Testing软件测试网x;Dp}suB
                     bunzip2 "$1" ;;
M8Q9?2? thm(c_d+_5k165731                           *) echo "File $1 can not be uncompressed with smartzip";;51Testing软件测试网MHW1I5}{Rt1n,X
                esac51Testing软件测试网rZ*{0?@.]
         您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。51Testing软件测试网 O0} U,Rp
也就是说,当我们运行:51Testing软件测试网"Q#j8w n%|V?V^
                    smartzip articles.zip51Testing软件测试网 m{ F pk g @
                    $1 就是字符串 articles.zip
.F M~#}gg.yL&c4z!e165731                3. selsect
M:RD7VoTOnL:h165731                  select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。
K~:o+{ fq z3B165731                    select var in ... ; do
#U-d]jf5w)W-?w165731                         break
a'iy/u)G;u"d ^`n165731                            done51Testing软件测试网!dqC.IJp
                            .... now $ var can be used ....
6Hn#z`lIh6n fa|165731                   下面是一个例子:51Testing软件测试网N%Y4\ I Q#J3ev)Q
                         #!/bin/sh
K.CF]4v;D F*{7o165731                         echo "What is your favourite OS?"51Testing软件测试网'F,ddZrp7jR
                         select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
^7` c1ygjGF1i)C165731                    break51Testing软件测试网b"a H(b?{ j HG
                                done51Testing软件测试网X1o] [crq9G}-U
                           echo "You have selected $var"51Testing软件测试网6rU+I @fuqR(P
              下面是该脚本运行的结果:
5sC&|HP165731                               What is your favourite OS?
V1t?Ziwh165731                                    1) Linux51Testing软件测试网6m/r \;x/S(h?,@
                                    2) Gnu Hurd51Testing软件测试网;`&m[;?a,L`
                                    3) Free BSD
^5d!q~,~1J)H"bv165731                                    4) Other51Testing软件测试网m?X }+R3_A
                                  #? 1
:UN-J*^S5@%`k165731                                You have selected Linux51Testing软件测试网%ftS%B-z5y+uG
         注:var是个变量,可以换成其它的值。break用来跳出循环,如果没有break则一直循环下去。done与select对应。
(m{n(S xZ;kF8B165731                  4.loop51Testing软件测试网u|ea%i
                      loop表达式:
%JQ\0l GQ165731                            while ...; do
}\J'lj5q&kag(K!\165731                                      ....51Testing软件测试网{+t'S_;{#Ppa
                               done51Testing软件测试网/D8}V[X)q
             while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true.51Testing软件测试网1Rbo)K$U(y9z
关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。51Testing软件测试网s4e+T4P)C/O
  51Testing软件测试网*Vs1|0} i;u$v~;{)l
                     for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量:
9Up}qj wnE0m165731                          1,   for var in ....; do51Testing软件测试网 tio'}})TMi
                                 ....
At)k x3dY0w165731                                done51Testing软件测试网/oM5f|VC
                       在下面的例子中,将分别打印ABC到屏幕上:51Testing软件测试网{'Kimi)C3Q
                            #!/bin/sh
H6j/k]&}1z165731                                    for var in A B C ; do51Testing软件测试网~ [ _;o7LK~
                                 echo "var is $var"51Testing软件测试网)m4taT'Bu'y ]Ib
                                     done
+X)o!hX.i+L16573151Testing软件测试网X:{Z,e;U
                           2,   for (( 条件一; 条件二; 条件三 );do
/\f'n9W7mdM165731                                ...
-q8W [0aj165731                                done
:uiZ:Z9i(tg}\165731                        例:
#] EO{#r$a:j H165731                     51Testing软件测试网5d$b qW6q6tr
                   for ((i=1;i<10;i=$[$i+1]));do51Testing软件测试网Hkj&}+c

_*M4m@ K9Zz165731                             echo "a"
g%_)W m4u YH9q{165731                          done51Testing软件测试网8P'n%i9f |ijK
输出:
$n1X,_+U*Er cn165731
OH_8mi5M-P E v?165731a
~M[F q/\165731a
;T7sp8P1IWV/F&_165731a
"K*^;^:OW4jvX165731a
v3E[r/f.[s(~6f165731a
9jW/V+o/X165731a51Testing软件测试网/rt+](| W m(PU-m'S
a
4]`h@9Y0o165731a51Testing软件测试网 iRi:`,oQ-h
a51Testing软件测试网]i*e~8q3U*YR

$_'Bn;L0\2sa1g R165731条件一:这可以看成是『初始值』,如上面的例子中,初始值是 i=1 啦!51Testing软件测试网HpOK F!YVE|"tp
条件二:这可以看成是『符合值』,如上面的例子中,当 i<=100 的时候都是符合条件的!
gt5hO1c#w.wB165731条件三:这可以看成是『步阶』!也就是说, i 每次都加一! 所以啦!上面的例子是说:由 i=1 开始到 i<= 100 ,每次 i 都加一来执行底下的程序段(就是 s=s+i ),当 i >100 (也就是 i=101 )就跳出这一段程序段!怎样!不难吧!51Testing软件测试网8y%CvN9gJ
51Testing软件测试网.aXwaoA Z0uX5b4h
51Testing软件测试网9L&C T F8hCG0Z1O*e

$l$U-M:hBi:J;s1s |165731
2Mf@fA:Q165731                        下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:51Testing软件测试网yeUp/s:E8_*j*g9YAc
                          #!/bin/sh51Testing软件测试网bh;IQ,Y`$P'|-G&g t
                          # list a content summary of a number of RPM packages
OC]l rS`g165731                          # USAGE: showrpm rpmfile1 rpmfile2 ...51Testing软件测试网 E2T f$M N'v\/v:r"a'u
                          # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
M [_kG1q [.gYE-D165731                            for rpmpackage in $*; do51Testing软件测试网!P3?/f*[|z ?*R
                         if [ -r "$rpmpackage" ];then
)R/\_~7G4t5{k165731                         echo "=============== $rpmpackage =============="
Z T;V)\ mA165731                          rpm -qi -p $rpmpackage
}nfV U!k165731                          else51Testing软件测试网sNp9LY+x;ug.B^
                           echo "ERROR: cannot read file $rpmpackage"51Testing软件测试网 YY u'~%bm$\3A
                         fi51Testing软件测试网f$nd*n5se3`.j
                              done51Testing软件测试网H,Ev,`.v2^
                   这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。
2y.h0v%_L}165731                        如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm
.vqJ'wpbLMd"N165731                                   此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm.
`/^(SJ;cIB.L9X165731
j&o n {5rfU6y/@Q16573151Testing软件测试网/L4h[V&^d:Ybv#\3hG

.lk u(bHzo0c.g165731『until:直到条件相同的时候才离开程序』;51Testing软件测试网8T1g8_6Z5bc"\6v5Li
『while:当条件相同的时候,就继续做!』  51Testing软件测试网%Pf)la[ {V/S

yov~i,f ?165731until [ condition1 ] && { || } [ condition2 ] ...
u4R1p5K4]B6u165731
L w,o p zF0G'[165731
%{-qKcdI(\16573151Testing软件测试网 CbCa9@
51Testing软件测试网p4LZ%p"z+J3H
                 5. 引号
U3[0[[kK T165731                   在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符(比如*)替换成合适的文件名,它变量替换成变量值。为了防止程序作这种替换,您可以使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件, mail.jpg 和tux.jpg。51Testing软件测试网)J _D]%cS"J#w&l
          编译SHELL脚本
J {bRK`*? qT165731          #ch#!/bin/sh mod +x filename51Testing软件测试网J-G6[3z8i7x
 cho *.jpg       ./filename 来执行您的脚本。51Testing软件测试网j.r:fi l+NV.I.X;{
  这将打印出"mail.jpg tux.jpg"的结果。
G'a3_y-E-\},vE{C165731    引号 (单引号和双引号) 将防止这种通配符扩展:
'e7UW#U\3e/Yuh&X165731             #!/bin/sh
nu2jT I"hz9g165731             echo "*.jpg"51Testing软件测试网&?T.{? @4[H-iN ]
             echo '*.jpg'51Testing软件测试网LK{sk,g*^
  这将打印"*.jpg" 两次。
K^S*l9Hz;Lm%?165731  单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。51Testing软件测试网Ytsv-K
         #!/bin/sh
zg#Vf"mLA0S6yu165731         echo $SHELL
$A.|1B:M6j8i'EC9?o:_165731         echo "$SHELL"51Testing软件测试网cBV%E~
         echo '$SHELL'51Testing软件测试网RJ(P!{ E}c
   运行结果为:51Testing软件测试网(S$c ^W O)v?
             /bin/bash51Testing软件测试网|;p!FK-g(_"K4r| D
             /bin/bash
6c,U(P1?p165731             $SHELL51Testing软件测试网M8oP:ukC
  最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:
j_LG^8l5h!`"Ru165731           echo *.jpg
xL6r%z.Xf165731           echo $SHELL
!E6Q5lHX*H|165731  这将输出:
#x5i J K0}165731           *.jpg51Testing软件测试网s!M&U j&d
           $SHELL
cjy?/Ju.s}N165731         6. Here documents
:_^f.J/mm/[165731          当要将几行文字传递给一个命令时,here documents(译者注:目前还没有见到过对该词适合的翻译)一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents就不必用echo函数一行行输出。 一个 "Here document" 以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:
:L~1bJ3MN165731         #!/bin/sh
3c^0Z(k!N9d4c165731         # we have less than 3 arguments. Print the help text:
|k `!R G165731            if [ $# -lt 3 ] ; then51Testing软件测试网G+B vf8E8\
                 cat <51Testing软件测试网z'}#ed/|4d;]giW
                 ren -- renames a number of files using sed regular expressions51Testing软件测试网vPD"Y*Y'e
                 USAGE: ren 'regexp' 'replacement' files...51Testing软件测试网H0Z+h.J5K
                 EXAMPLE: rename all *.HTM files in *.html:51Testing软件测试网 J#@|;n\W9V
              ren 'HTM$' 'html' *.HTM51Testing软件测试网3`V-NJoVgw
                 HELP51Testing软件测试网J`7j M0i5o'j
              exit 051Testing软件测试网)T'd$_*u-nf*S.uS
            fi
"Ax_ pry KXl165731            OLD="$1"
&V$CD#I1trwZM165731            NEW="$2"51Testing软件测试网Go4qt(})Y)a2Rq7g
          # The shift command removes one argument from the list of
yQ#JY v%d[5l165731          # command line arguments.
X6\1m4pL8U\4W165731          shift
TWfg"r165731          shift
.X`;`Yuz$D%N165731          # $* contains now all the files:
JuQ0bNx|165731         for file in $*; do
+s6OV-u/r`X%h(W l165731          if [ -f "$file" ] ; then51Testing软件测试网9uU5A,P+d1M7V"N
             newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
o\:t6R%gl H4z165731             if [ -f "$newfile" ]; then
Q(LX)dK+u165731                  echo "ERROR: $newfile exists already"
ft%Fn Hb@165731             else
B4ZYxP`l165731                  echo "renaming $file to $newfile ..."
4J1l P8yKs165731                  mv "$file" "$newfile"
5s5pK4VvZ165731              fi
m']b(Q%P!p8Q~i165731            fi
K"Dp {/p[165731           done
[WR6|!h%eq#]i4zh7K165731        这是一个复杂一些的例子。让我们详细讨论一下。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了我们的目的:得到了旧文件名和新
&J I'[D1S165731文件名。然后使用mv命令进行重命名。51Testing软件测试网P4|;U"Md
          4)函数
#MN }"KQ'L165731             如果您写了一些稍微复杂一些的程序,您就会发现在程序中可能在几个地方使用了相同的代码,并且您也会发现,如果我们使用了函数,会方便很多。一个函数是这个样子的:51Testing软件测试网*@~9L o,T K
          functionname()
p:y7i%k1yB \O165731          {51Testing软件测试网,l+N}xI7?0@!\Y5A{
                 # inside the body $1 is the first argument given to the function
3Fae j-F165731                 # $2 the second ...
.dNf7@/z8L(J&sC&t165731                             body51Testing软件测试网]r2B:O~ o1y
            }
Qs6`j @v(a165731          您需要在每个程序的开始对函数进行声明。
gRK'SII2z C165731   下面是一个叫做xtitlebar的脚本,使用这个脚本您可以改变终端窗口的名称。
)I^ [AY%x165731           这里使用了一个叫做help的函数。正如您可以看到的那样,这个定义的函数被使用了两次。
;yI q8` Or1B]k165731               #!/bin/sh51Testing软件测试网P X"M9dI(u\
               # vim: set sw=4 ts=4 et:
v ?@?r:]8g@165731               help()51Testing软件测试网g*H4Dh g6T|
               {
t3{pdl~S X~b,p165731              cat <51Testing软件测试网t.V}6C {$^:^} QV$Z
                     xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
G2z)?%qg165731                     USAGE: xtitlebar [-h] "string_for_titelbar"51Testing软件测试网6_N,}2j:W,Wg
                      OPTIONS: -h help text51Testing软件测试网9Q t;_e6W8wQ)~
                     EXAMPLE: xtitlebar "cvs"
e V:w"GQ;\fp Z0z(yyhF165731                     HELP
M;hc;kCB['ap-W165731             exit 0
S'\U] ZpA165731               }51Testing软件测试网d,h'K0b eq#S4S0|n3o6{
               # in case of error or if -h is given we call the function help:
-UUBks165731               [ -z "$1" ] && help51Testing软件测试网&hcF[$xZ9_q
               [ "$1" = "-h" ] && help
4e _:Nsx1W+^m H J165731               # send the escape sequence to change the xterm titelbar:
YY.PesO6^165731                 echo -e "33]0;$107"51Testing软件测试网l} z"W&R`nA
                #51Testing软件测试网:s Nm"pV+s['n
            在脚本中提供帮助是一种很好的编程习惯,这样方便其他用户(和您)使用和理解脚本。51Testing软件测试网Z4_1w,VU
        命令行参数51Testing软件测试网G C;^A7Jf:[a
  我们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强制性的参数和查看帮助的-h选项)。但是在编写更复杂的程序时,您可能会发现您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后面再加上参数值 (比如文件名)。有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无遗是一个不错的方法。51Testing软件测试网Q];M2F O#HJ(z(j0P
         #!/bin/sh51Testing软件测试网?Gn7iOL"{ h z
         help()51Testing软件测试网 \$i0UcZ0bPE
         {
1I/A vB(Q7A9f165731            cat <51Testing软件测试网ds{)S_y.H
               This is a generic command line parser demo.
lyNmgp165731               USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile251Testing软件测试网,J"X]x+S.y"u%_(D3g
               HELP
VK%r M c"Qs165731            exit 051Testing软件测试网PO,oBz"_:^
         }51Testing软件测试网.SF1c c6d6M\ C
          while [ -n "$1" ]; do
n da"G}l/M165731        case $1 in51Testing软件测试网#nOy|1kq+H
       -h) help;shift 1;; # function help is called51Testing软件测试网n_)lzV~*LC@a1s$]
       -f) opt_f=1;shift 1;; # variable opt_f is set51Testing软件测试网7NXA"l m b
        -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 251Testing软件测试网Q"h5Wy4G
        --) shift;break;; # end of options
7i-F-rUS8|-Y*H165731       -*) echo "error: no such option $1. -h for help";exit 1;;
@.G$VD[;H7T165731       *) break;;51Testing软件测试网;v$D7[.M0d`'y%r!j
          esac
3uDIV[y165731          done
i}wAa-s"y&[K8I165731          echo "opt_f is $opt_f"
p_ g$Y*z9U#_W U165731          echo "opt_l is $opt_l"51Testing软件测试网hC } Z8jG:b6G e
          echo "first arg is $1"51Testing软件测试网 n T sw:pb4f2rG
          echo "2nd arg is $2"51Testing软件测试网*PK0m2`1f([-I#@Ku
  您可以这样运行该脚本:51Testing软件测试网9U2l_Y#W!gf9wT-}
                 cmdparser -l hello -f -- -somefile1 somefile2
&B@we4T165731  返回的结果是:51Testing软件测试网p'|9Xji6N
             opt_f is 151Testing软件测试网T H8iV.]*FU
             opt_l is hello51Testing软件测试网 Uq[ KM,u.X
             first arg is -somefile151Testing软件测试网9]5E/x_ z+lK
             2nd arg is somefile2
\$g2}5_*BGuj165731  这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数.51Testing软件测试网$T h6{.?i N9keJ
51Testing软件测试网o _:dDug8R.q

E,yb5N tp`-e&WT165731第2部分 实例51Testing软件测试网^k-l^;r|d0J

MXp,[;IC/@[b165731    现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下copy命令:
LK!f@r8Y&CA|h165731cp framework.sh myscript.
FI Un#[,O_165731 然后再插入自己的函数。51Testing软件测试网$]eO@#_|M
  让我们再看两个例子:
&ew \s!He-U$ik.a5YAb165731  二进制到十进制的转换
5t F"g_Rz9Gx165731  脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:51Testing软件测试网j)? e` A Z
#!/bin/sh
|1u @$G.V ^t165731# vim: set sw=4 ts=4 et:
;V}!}p5J*A-Fco165731help()51Testing软件测试网 Y7zf3PQPjO
{51Testing软件测试网|2o.d DTn
 cat <
-mO'uJazi&VMd165731b2h -- convert binary to decimal
]k:b$~h165731USAGE: b2h [-h] binarynum51Testing软件测试网8u$rcx }B
OPTIONS: -h help text
%s{G-F'U*p I1Y8M165731EXAMPLE: b2h 11101051Testing软件测试网J5}6R%BR1xiz
will return 5851Testing软件测试网S4~.uu#] zW
HELP
3a*OD'{Y(~8C"eXZ165731 exit 0
0HL*n'@RNlE_Z\165731}
2Zu2^3Emhe165731error()
A w!O4n0br'TX165731{51Testing软件测试网 `la$O.rzHY
  # print an error and exit
aM5O+USSLzB S165731  echo "$1"
5Ir't5T9O.t4N8P8j165731  exit 1
6@`;lq*N4c"AE165731}51Testing软件测试网;gI&rY\&Y}
lastchar()51Testing软件测试网$Hf`Q7N
{51Testing软件测试网5G%Q?7X+bD"x
  # return the last character of a string in $rval51Testing软件测试网DlA4p+Z8a9HC s[2]D
  if [ -z "$1" ]; then51Testing软件测试网 U/\g2V8J~5Aa E9C
    # empty string51Testing软件测试网mM(n AZG
    rval=""51Testing软件测试网V5S {y;S
    return51Testing软件测试网 vk*WL ]S9f'r R
  fi51Testing软件测试网2XYE@8{2Gx
  # wc puts some space behind the output this is why we need sed:51Testing软件测试网;`GN(nr(ev
  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
7_'U9O,B5Wh.t ]]'u165731  # now cut out the last char51Testing软件测试网 Z&Y.R]p$s7P}%O;eI'C
  rval=`echo -n "$1" | cut -b $numofchar`
;S1r-f_/N;z&w165731}51Testing软件测试网bZd4m9e
chop()51Testing软件测试网*l2H$O-f }?_"Zr9N9Z`
{51Testing软件测试网p)R1Z%NLfY ac`U
  # remove the last character in string and return it in $rval51Testing软件测试网FN+``ga0[FI
  if [ -z "$1" ]; then51Testing软件测试网 |qInc.WP-KX
    # empty string
EL j+?d165731    rval=""
(kcCAJG%C_GF165731    return51Testing软件测试网 M,SH8C'`8h|
  fi
n V/s l,o9O165731  # wc puts some space behind the output this is why we need sed:51Testing软件测试网m'c&Di^ sZ2w1k_
  numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
3Y r/t-E K VgO)f.h165731  if [ "$numofchar" = "1" ]; then
F/_!}u)hk#p165731    # only one char in string
@%Wd'p9g}165731    rval=""51Testing软件测试网a+y La VP
    return
)^.I:_ Yo165731  fi51Testing软件测试网g`MY)bV;{
  numofcharminus1=`expr $numofchar "-" 1`
5q1s o7C0J O,?~ n165731  # now cut all but the last char:51Testing软件测试网a kMxXu:g g$V!e!f
  rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`51Testing软件测试网?0y-W"zQMb
}
d-nb{ ^6l5A165731while [ -n "$1" ]; do
6K/Kt g iQc zk*Q165731case $1 in51Testing软件测试网9~:ZG|~;t*dJ
  -h) help;shift 1;; # function help is called51Testing软件测试网z7^ d;y g-bz[xw
  --) shift;break;; # end of options
G'Q%IZ@)T&}Sb(m165731  -*) error "error: no such option $1. -h for help";;
NU`wUoT T,T165731  *) break;;
(Q7{nKzfmJ165731esac51Testing软件测试网5aY%G%\s:t
done51Testing软件测试网g9yua4`D.\
# The main program
$ER*W|C ?'H*o&j165731sum=051Testing软件测试网'YL!k8["W(u~
weight=151Testing软件测试网cl+V"w V*rk
# one arg must be given:51Testing软件测试网%k_7mEd.yv(m
[ -z "$1" ] && help51Testing软件测试网 T,|A,e5E%Vkq\[
binnum="$1"
F)_e3_ J ?165731binnumorig="$1"51Testing软件测试网ZmX8o|j C
while [ -n "$binnum" ]; do51Testing软件测试网2K Hs/P0O9u+xK,F
  lastchar "$binnum"
/h VU:L{`K165731  if [ "$rval" = "1" ]; then51Testing软件测试网L'BL9A,K;A?%R%W
    sum=`expr "$weight" "+" "$sum"`
_I _?4d~A165731  fi51Testing软件测试网*h6aJE%}k
  # remove the last position in $binnum
w'~^ N*l4H165731  chop "$binnum"51Testing软件测试网+lmr`Yj:w
  binnum="$rval"
1p&t0paQ165731  weight=`expr "$weight" "*" 2`
w-nGrm_l1J165731done
7{3_0c-m#C |.j0m165731echo "binary $binnumorig is decimal $sum"
d b N?gJs9c165731   该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制:51Testing软件测试网6SNN$@XjU#Ni
0 * 1 + 1 * 2 = 2
s0b(A"P |'J9

TAG:

 

评分:0

我来说两句

Open Toolbar