$7.49 .com domain with free InstantPage Website Builder$1.99 Web Hosting   捷飞网络官方淘宝店   Godaddy 优惠码
返回列表 发帖
分享到:




[应用&技术] 关于linux 的shell script 系统学习

在DOS 中,你可能会从事一些例行的重覆性工作,此时你会将这些重覆性的命令写成批次档,只要执行这个批次档就等於执行这些命令。大家会问在UNIX中是否有批次处理这个东东,答案是有的。在UNIX中不只有如DOS 的批次处理,它的功能比起DOS 更强大,相对地也较复杂,已经和一般的高阶语言不相上下。在UNIX中大家都不叫做批次档,而叫做Shell Script。
# R* G& I7 {6 I, j( y$ a% F6 S5 i    一般而言,Shell Script的地位和其它的可执行档(或命令)是完全相同的,只不过Shell Script是以文字档的方式储存,而非二进位档。而执行Shell Script时,必须有一个程式将其内容转成一道道的命令执行,而这个程式其实就是Shell ,这也就是为什麽我们叫做Shell Script的原因(往後我们称为Script)。不同Shell 的Script基本上会有一些差异,所以我们不能将写给A shell 的Script用B shell 执行。而在UNIX中大家最常使用Bourne Shell以及C Shell ,所以这堂课就介绍这两种Script的写法。   K& L4 A3 [6 U3 c& |$ e# G
    将文字档设为可执行的Shell Script + `7 H% ~( w+ N% U2 p
    如果我们已经写好Script,如何将其设成可执行档呢?因为Script其实是一个可执行档,所以必须将其存取权设定成可执行。我们可以使用下列命令更改存取权: ' E# _& m6 r& @2 d
    chmod u+x filename 只有自己可以执行,其它人不能执行
$ {' y! s& G" r$ D3 W, P    chmod ug+x filename 只有自己以及同一群可以执行,其它人不能执行
" ^# m5 t  r% o( W% y    chmod +x filename 所有人都可以执行 3 A9 V- W# G8 @) E
    而我们如何指定使用那一个Shell 来解释所写的Script呢?几种基本的指定方式如下所述:
- u* U* Z  a1 B! `7 R    1. 如果Script的第一个非空白字元不是"#",则它会使用Bourne Shell。 6 a: ^9 _3 i. d. o0 O' |, A
    2. 如果Script的第一个非空白字元是"#"时,但不以"#!"开头时,则它会使用C Shell。
- ~/ P1 F' v8 _' B$ j    3. 如果Script以"#!"开头,则"#!"後面所写的就是所使用的Shell,而且要将整个路径名称指出来。 + O% u- S+ ]1 h
    这里建议使用第三种方式指定Shell ,以确保所执行的就是所要的。Bourne Shell的路径名称为/bin/sh ,而C Shell 则为/bin/csh。 3 P1 T+ L* g" \6 k3 E, {
    1. 使用Bourne Shell
4 Y  @1 A5 @! Z9 V0 V$ t2 }    ┌——————————┐ ┌——————————┐
4 V5 k. b7 x$ e$ m# h' @    │echo enter filename │ │#!/bin/sh │
2 J1 ?( {; ~# G  D& q    │ . │ or │ . │
: A( ?7 B8 i  ]& h3 \( ?0 W4 e    │ . │ │ . │
( R. i4 b/ g/ _$ @! O% }    │ . │ │ . │ 9 }( m3 C0 o8 Q$ x
    └——————————┘ └——————————┘ % o1 E& L. c+ t6 L/ K- O" A
    2. 使用C Shell ) w1 y* p; @+ W
    ┌——————————┐ ┌——————————┐
( v" \+ S( a+ |, c  m    │# C Shell Script │ │#!/bin/csh │
/ W2 B: X; E- H" W    │ . │ │ . │ 1 ^5 z5 L4 I" y. W! q
    │ . │ │ . │
- ^8 a% x# C- E) u3 B3 H* k5 N1 v    │ . │ │ . │
! E' x. V4 d" i2 a+ U    └——————————┘ └——————————┘
8 r; Y3 C4 A9 ]9 ?; p  z+ g9 y    3. 使用/etc/perl & K1 ^( j1 j; Y8 C' Y
    ┌——————————┐
. a' S% u" @7 t3 J$ |1 x    │#! /etc/perl │
! \) z/ K: Y  L6 R  x  ~6 `) e    │ . │
; \- U9 m3 g' _1 r; g# ^/ E' U7 @" V    │ . │
0 l2 S  F1 i* Y  b8 o  y0 ^    │ . │ & Z: L  i+ z2 U( ]
    └——————————┘ + g2 d0 t% p; r; H& A
    除了在Script内指定所使用的Shell 外,你也可以在命令列中强制指定。比如你要用C Shell 执行某个Script,你可以下这个命令:
3 g1 K7 \9 w' v& B  Y$ q1 v    csh filename ; h- W* @+ P' |$ h2 _  _
    此时的Script的存取权就不一定要为可执行档,其内部所指定的Shell 也会无效,详细的情形後面会讨论。 + L# X" ^  r7 [  R
    □Script的基本结构及观念 ' {( I4 \( t' r5 l4 d1 T
    Script是以行为单位,我们所写的Script会被分解成一行一行来执行。而每一行可以是命令、注解、或是流程控制指令等。如果某一行尚未完成,可以在行末加上"\" ,这个时候下一行的内容就会接到这一行的後面,成为同一行,如下
2 z4 F& u# D' z2 n7 B    ┌———————————┐
1 G. H/ C0 e( C( M( l  t: a: i    │echo The message is \ │
  x) [+ O% \; z- C% p3 \8 Y6 Q; o    │too long so we have \ │
, }6 \2 W- _* L. k    │to split it into \ │ ) ?; s+ Q: Z  N; V
    │several lines │ 3 j2 D0 g  }. O9 c. O
    └———————————┘
' Q7 n+ H5 g5 J( [" `6 h    当Script中出现"#" 时,再它後面的同一行文字即为注解,Shell 不会对其翻译。
: M& t: I2 l: U1 t2 P9 I    在Script中要执行一个命令的方法和在命令列中一样,你可以前景或背景执行,执行命令时也会需要设定一些环境变数。
) {! t* _5 ~6 N0 X; c8 q    Script的流程控制和一般高阶语言的流程控制没有什麽两样,也和高阶语言一样有副程式。这些使得Script的功能更加强大。 6 z' K( W: A  o9 |7 v
    为了达到与高阶语言相同的效果,我们也可以在Script中设定变数,如此使Script 成为一个名付其实的高阶语言。
& l$ ~! w& U+ q  ^9 b# o    □Bourne Shell
8 P$ X9 O& E0 B) b    一、变数
0 j  l+ U5 D5 `2 Y    Bourne Shell的变数型态只有字串变数,所以要使用数值运算则必须靠外部命令达 成目的。而其变数种类有下列几种: 3 [  S3 O2 V  ~8 R
    1. 使用者变数 7 e% E( J$ x+ K
    这是最常使用的变数,我们可以任何不包含空白字元的字串来当做变数名称。 设定变数值时则用下列方式: 1 g- q$ ^) |! i
    var=string
9 ]& H+ U4 l6 D: f4 l% q    取用变数时则在变数名称前加上一"$" 号。
8 t* S: A! ?; k    ┌———————┐
1 l& i; A! v. M- y: \# N    │name=Tom │ + K+ Z( v+ ]1 L$ K8 E
    │echo name │ / D3 c% H" d8 R1 {
    │echo $name │
- C9 i  k0 n$ o/ v7 v! u# V( z% {    └———————┘
6 P& O* z0 ^" _; Y; v    结果如下: ' f5 U7 x0 h- I* ]
    name / p$ R) m& Q% x- \+ r! a
    Tom
3 X* ]0 z" o# r6 @2 c    2. 系统变数(环境变数) 5 ^9 z! M! w7 k9 V, c
    和使用者变数相似,只不过此种变数会将其值传给其所执行的命令。要将一使 用者变数设定为系统变数,只要加上:
+ u9 J: X0 I% o) [0 U    export var * ]1 O0 E( y+ n8 G
    ┌———————┐ & Q3 g/ H6 u" P( g
    │name=Tom │
) u& @* B2 {% S0 E    │export name │ 6 Z* N* G1 }/ I
    └———————┘
8 v5 i" k& ]( `4 ]$ b1 G% ?* u- }0 t    以下是使用者一进入系统之後就已设定好的系统变数: # S/ X4 @- S5 u9 n" |
    $HOME 使用者自己的目录
. ?0 U6 v- ]4 J- z, A5 Z    $PATH 执行命令时所搜寻的目录 * O6 j: P( `" Z+ _8 K& l3 j
    $TZ 时区
: L0 t5 j2 F5 q" L. `3 @" }    $MAILCHECK 每隔多少秒检查是否有新的信件
" f; d: L2 ?4 F0 g: h' D5 P    $PS1 在命令列时的提示号
* p. ?! T. a2 C$ x1 V( N* c    $PS2 当命令尚未打完时,Shell 要求再输入时的提示号 7 _6 h. d5 \) q8 f) L3 d
    $MANPATH man 指令的搜寻路径
3 j' U0 V5 o) B5 y    3. 唯读的使用者变数
8 y) x1 _" N: E( g8 x. {# H    和使用者变数相似,只不过这些变数不能被改变。要将使用者变数设成唯读的 ,只要加上: . u' [! d! Z; P1 J+ V: x
    readonly var
) H) D. y6 u6 e, D; Q    而若只打readonly则会列出所有唯读的变数。还有一点,系统变数不可以设定 成唯读的。
* }1 X& M$ y: S' P- L) G7 f+ l    ┌———————┐
5 m! I5 h5 E( J    │name=Tom │
% b- x9 q% i7 j1 T; x. Z    │readonly name │ 6 }0 m  p( J. j5 s' F" d
    │echo $name │
5 K& V0 t/ N' |4 k9 B- l  o( n    │name=John │ 7 B+ D; d8 l4 @( Y
    │readonly │ - n& V* `' t/ J# r; l! M
    └———————┘ " K7 B0 F, ~5 a2 O
    结果如下:
+ R3 z1 S- C& y    Tom
6 \- O% G6 H% y1 Z    name: is read only
: w/ C* T# D( \7 P' _" _4 s% N    readonly name
, Y/ }- R- }) ?9 I' M    readonly ......
+ J: P) t" c3 K2 H. o7 @8 y+ H    4. 特殊变数 - J( t: p0 Z! f" N# ^
    有些变数是一开始执行Script时就会设定,并且不以加以修改,但我们不叫它 唯读的系统变数,而叫它特殊变数(有些书会叫它唯读的系统变数),因为这 些变数是一执行程式时就有了,况且使用者无法将一般的系统变数设定成唯读 的。以下是一些等殊变数: 2 F7 W4 ?0 ?( K, Y3 a2 E
    $0 这个程式的执行名字
/ ~; r$ r' V, @* ^2 I" t+ z: a2 {    $n 这个程式的第n个参数值,n=1..9
  z+ e: ~( C6 t- r9 l0 n* h( b, w    $* 这个程式的所有参数 - L& I, P7 y% k* P# I% F
    $# 这个程式的参数个数
- H$ C& y$ N1 j' K    $$ 这个程式的PID
0 y- W% k8 B; {$ o    $! 执行上一个背景指令的PID
; i; d5 {7 s: ?/ A; e$ T8 J6 Q; K    $? 执行上一个指令的返回值 ( p4 B' K/ a) x
    当你执行这个程式时的参数数目超过9 个时,我们可以使用shift 命令将参数 往前移一格,如此即可使用第10个以後的参数。除此之外,吾人可以用set 命 令改变$n及$*,方法如下:
6 _, h/ t7 V9 J. L) Y  w    set string
* Y) Y: w0 B: ?8 ?2 S3 t; c    如此$*的值即为string,而分解後则会放入$n。如果set 命令後面没有参数, 则会列出所有已经设定的变数以及其值。
) u, L1 d0 g9 c) b9 L    档名:ex1 参数:this is a test + Q, q$ S( Z" V2 N! ?
    ┌———————————┐
' t& [) I% [6 L( G# {5 b: w    │echo Filename: $0 │
5 n  r% v( }0 k2 P& M+ u    │echo Arguments: $* │ 6 W# L! y. C6 E9 ?) \+ R* Q, R/ p3 m
    │echo No. of args.: $# │
- G6 g) j8 p) w  Q( r% \7 U    │echo 2nd arg.: $2 │ - q2 m( l# N2 [6 Y2 }4 s# l3 M
    │shift │
8 e$ Z7 e+ A4 d2 R% g/ C7 a1 r4 x$ X    │echo No. of args.: $# │ 1 [/ T0 ?9 I% e. g; M$ [
    │echo 2nd arg.: $2 │ 7 |! q: N& S# s" f5 F
    │set hello, everyone │
' I$ w% O# V4 s$ g1 X& }4 B  A    │echo Arguments: $* │
$ n( z5 @" l; w+ K" n3 P8 S# H    │echo 2nd arg.: $2 │ * a: s/ t8 m0 B+ [7 x; n8 i) n
    └———————————┘ $ g# h5 A) t% l7 D. z7 L
    结果如下:
- M5 f2 f5 y; z" l" ^    Filename: ex1 8 q/ k) n7 {% |2 d$ d7 Y/ P3 `; T
    Arguments: this is a test 0 r. b# s1 U6 N* H- d
    No. of args.: 4 ' L9 P1 z2 F/ B& E+ t
    2nd arg.: is
9 K# R6 E# s0 j    No. of args.: 3 0 K6 B+ a* J3 y  x; F
    2nd arg.: a 8 J5 y" y& h, [9 k% ?
    Arguments: hello, everyone 4 l/ r2 w6 ]5 v% I9 X8 X4 S
    2nd arg.: everyone + q% r" w  h( _, {, r5 T% H
    值得一提的是,当你想从键盘输入一变数值时,你可以使用下面的命令:
$ `) V" x( P. R/ N) K5 k: q7 X    read var1 var2..... 8 X7 v& d0 L* e3 B- _
    这时read会将一个字分给一个变数。如果输入的字比变数还多,最後一个变数会将剩下的字当成其值。如果输入的字比变数还少,则後面的变数会设成空字串。 如果需要处理数值运算,我们可以使用expr命令。其参数及输出列於附录A。
. ~3 m, N6 \8 C! ~# w& E/ [    二、执行命令   y4 f& m. c" l7 `6 }& f
    在Bourne Shell中有五种方法执行一个命令,而这五种方式所产生的果有些许的不 同。
& k" M9 T1 e* M! i4 A% Q! p6 }% g    1. 直接下命令 0 j7 V1 k. l0 D; \7 \0 g- a
    这个方式和在命令列中直接下命令的效果一样。
7 r# B$ R5 {9 L8 \% w+ K    2. 使用sh命令 , |9 M9 D1 f  P% h1 r
    sh command
: \9 \8 M3 j; e8 O0 R    这个档案必须是Bourne Shell的Script,但这个档案并不一定要设成可执行。 除此之外和直接下命令的方式一样。
4 z1 i. a, v9 D; Y) E+ I7 L    3. 使用"."命令
$ C/ G  P- u2 C    . command ) J0 ]: L: X' k: |/ ~  O- Z, z
    这时和使用sh命令相似,只不过它不像sh一般会产生新的process ,相反地, 它会在原有的process 下完成工作。 ( x) K$ |4 g! }4 J+ p1 [
    4. 使用exec命令 . F! x- K) v  Q" y2 f! a
    exec command - |+ W1 J* Z3 I, w+ s) x
    此时这个Script将会被所执行的命令所取代。当这个命令执行完毕之後,这个 Script也会随之结束。
) L" ~5 ^7 H; s2 x2 Q2 T    5. 使用命令替换
; S3 Q. [6 z# n; o* p+ }' c    这是一个相当有用的方法。如果想要使某个命令的输出成为另一个命令的参数 时,就一定要使用这个方法。我们将命令列於两个"`" 号之间,而Shell 会以 这个命令执行後的输出结果代替这个命令以及两个"`" 符号。 + t  G! h, z# A( U
    str='Current directory is '`pwd` + _4 U3 k5 s9 T. P) [+ b
    echo $str # a& z; R' k) g# u! w9 E! B- ~2 [
    结果如下:
% Z8 w; ?* g; \- T/ Z' C    Current directory is /users/cc/mgtsai ! W' n. `" v  q8 p2 S" o
    这个意思是pwd 这个命令输出"/users/cc/mgtsai",而後整个字串代替原 来的`pwd` 设定str 变数,所以str 变数的内容则会有pwd 命令的输出。 6 @" B' c8 |! L, E
    number=`expr $number + 1` - p# q+ G1 F$ {2 f& T3 O: h! a
    这就是先前所提要作数值运算的方法,基本上expr命令只将运算式解,而 後输出到标准输出上。如果要将某变数设定成其值,非得靠命令替换的方 式不可。这个例子是将number变数的值加1 後再存回number变数。
' d  x# ^" k( M. n7 G  ]    三、流程控制
0 l8 e- [1 b( ]' K    在介绍流程控制之前,我们先来看看test命令。test命令的参数是条件判断式,当 条件为真时则传回非零值,而条件为伪时则传回零。在所有的流程控制都必须用到 test命令来判断真伪。而test命令的使用方法则列於附录B。
1 f9 V; ~1 k5 d- E+ N* q    test $# = 0
  d. B0 i7 ]" a' L4 \$ w    如果执行这个程式没有参数时,会传回非零值代表"$# = 0"这个条件成立。反 之则会传回零。
1 a, M# P  o8 v7 P! o. o3 _& F    以下介绍各种流程控制:
0 \+ Z& s/ E8 b9 k# u/ V. G' |( |    1. if then语法以及流程图如下 " `! _6 @6 a; @& a- k
    │ FALSE
- F9 d  V* k; V3 m; t2 Z    if (condition) <condition>—┐ 1 R/ A. Q2 f) ?9 e8 _7 q" r
    then │TRUE │
$ U/ o8 _& I5 n" H4 T, h$ A    then-commands then-commands │ , z; c1 V# b( p/ R5 a
    fi ├————┘
8 E$ h8 m' J8 E* }) ?( S    │
3 t; J. U4 I: s4 B7 x9 k, b" x    condition 是一个test命令。往後所介绍的各种流程中的condition 都是test 命令。 8 L9 c9 u3 ]7 a1 X4 {5 |/ t
    档名:chkarg $ b. ?: K7 G; D7 K! y
    ┌———————————┐
- }7 ~, J: e$ v6 ~- n1 w    │if (test $# != 0) │
' \! Z& Z. }6 H* S    │ then │
8 I) X* s+ B- Q# C1 T4 q    │ echo Arg1: $1 │ 5 O# x; T$ d% Q$ k+ `5 L
    │fi │
9 u0 L" v6 Z' {    └———————————┘
4 h! C8 f; ?# ~    $ chkarg Hello
4 T& Q9 w# X  E5 u/ [. a6 b) N    Arg1: Hello % ?# l0 p# z6 C: V1 s
    $ chkarg % r3 }/ X" I' A" x( |
    $ ; t: P# p% y0 N* A
    2. if then else语法以及流程图如下 ' v9 i; w) T" t! \
    │ FALSE
4 L  }3 T. k/ T7 ~: ~* t    if (condition) <condition>—————┐ ' Y2 a% x+ M1 ~- z! ~- v2 Q. {
    then │TRUE │ ) A$ P* B. E6 S9 c
    then-commands then-commands else-commands 3 J* C! t' G/ b" ~
    else ├————————┘
% v! w9 E" o6 |2 X* ^) X) |    else-commands │
, ^" n! f& n- f# o$ ]! O" F    fi
  Y) k: P! a7 V  Q. o1 G    3. if then elif语法以及流程图如下 - o7 G9 O( _1 S2 v% S& K, J6 C( ^
    │ FALSE
/ s+ F: ~4 r0 h& O( r; n) E2 I    if (condition1) <condition1>—┐ + G  c* Y2 {# [7 W
    then │TRUE │ FALSE
2 k" @4 @- z6 b: ]! i# l    commands1 commands1 <condition2>—┐   }9 S0 ^' X4 M, L
    elif (condition2) │ │ TRUE │
8 o! O1 Y5 L" V0 H: _9 U    then │ commands2 commands3 0 Z$ @+ ?$ s0 n' z: U$ r
    commands2 ├—————┴————┘
: K" S, N; k$ u8 [. O    else │
4 T' ^) \' T2 c9 g6 q    commands3
7 ]- Y. t& U1 `" |9 M% K. V7 e    commands3 ( x# t7 k. _/ G& V- r; R. ^
    fi
. z- u. u. O% ?% v- P6 ]; Z    echo 'word 1: \c'
0 {9 \" [+ ]( R1 C7 k% n8 ]! ]    read word1 ! @# w  u9 v' R% o
    echo 'word 2: \c'
% |, ~4 N) g, y9 |    read word2
% r$ n# b9 {/ W: \; N9 H: I. V7 Q    echo 'word 3: \c' & Y1 `# W( e, d$ |; V
    read word3 ! `1 W9 L# P8 @& ~! _# E
    if (test "$word1" = "$word2" -a "$word2" = "$word3")
3 j" h* B# e$ K    then
$ M, W- m, a& j7 n1 O! V    echo 'Match: words 1, 2, & 3'
' o3 B9 F- J! n" V* T    elif (test "$word1" = "$word2")
! B" o6 b  F& s9 k" D% N  e  D" z    then
; ^5 e& G# [" n    echo 'Match: words 1 & 2' - v. l: L) i+ r) A: d
    elif (test "$word1" = "$word3")
5 j3 P# L1 V  c4 w/ G; y    then
( K  A  W7 ?4 u9 u$ ], r+ p    echo 'Match: words 1 & 3' 3 r( R- a' b7 ?% `$ h5 W
    elif (test "$word2" = "$word3") # ~0 ?- Z2 B( o2 O- W/ J# J
    then 9 R" f* p/ F+ H# ^3 _8 S' l: u
    echo 'Match: words 2 & 3' ' ^7 _$ E, N' k, l
    else 1 Z) v/ H. E5 K. a
    echo 'No match' * Y4 ^/ e8 E: B' J- I
    fi * L' y. P( B" V% Q8 s- c# \, @
    4. for in语法以及流程图如下 ' _9 x" {7 N& @/ W3 a1 h
    │ FALSE
: N/ j+ n8 A0 }1 ~4 f% B+ d. n    for var in arg-list ┌—<arg-list还有东西吗?>—┐ ' Z. Z" F6 |" \$ y
    do │ │TRUE │ 8 |" \8 f- Q# W2 Q  Z6 K
    commands │ 从arg-list取得一项 │ ) G' n. Y: d% C- p5 M
    done │ 放到变数var │
9 f0 K4 z+ M  Q+ [+ _+ G    │ │ │
) [+ c' A) r% F& D! h    │ commands │ . O4 ]4 b- t3 Z
    └——————┘ │
, l% u4 k- @' f    ┌———————————┐ ┌—————┘
9 x$ c% ^3 q  t9 ]9 d; W- X" G/ ]; J3 e    │for a in xx yy zz │ │ / h: t0 U1 K! B9 x
    │ do │ 9 c4 Y  P" I: |4 |  n1 T0 S
    │ echo $a │
. s$ h0 y- G/ q8 j! C' b# J4 N    │done │ ) R% w; Y3 ?( z% y
    └———————————┘ 3 k+ g* ~+ N& v, U% n
    结果如下:
$ U- |& N8 i( s0 X. i, \    xx
2 v) L$ R" D' P" o7 {% v    yy
0 v& {0 G' z# W- @9 k5 n    yy
( l) n; o& w( }6 H7 c    zz
' D7 Y1 B" A+ f% c    5. for语法以及流程图如下
0 t! n) {* k" N    │ FALSE 9 j, }. o: q" b  q7 Z/ W
    for var ┌—<参数中还有东西吗?>—┐
: _8 b7 y4 G- i) ^    do │ │TRUE │
* Y, o: v4 x, U$ M) d    commands │ 从参数中取得一项 │
- e; h6 W  `- n    done │ 放到变数var │
( \) n! u3 v' g6 S6 U2 _    │ │ │
* [" C" i- A: D; F6 B$ _% ?' y0 e    │ commands │
4 s5 _: q! u; [) E    └—————┘ │ / x) M. k- B# w4 Z: d
    档名:lstarg ┌—————┘
6 k! w+ B, k( ~) s% v* x1 |5 ^    ┌———————————┐ │ 9 [( v' L  y, e  ^4 l3 r
    │for a │ 3 d( Q9 m! U  B% u4 x+ n
    │ do │
+ o/ H7 |% C( N$ d% P$ ]0 E9 l    │ echo $a │ ( |. ]1 ^$ p- u% ]
    │done │
. j" j( O& S8 E+ A% |" ?    └———————————┘ & n2 y9 O/ q. N* c
    $lstarg xx yy zz
) a+ N  M9 e6 d7 B; `  L) H    xx
( W0 f8 t* v( q& n6 c3 }; }    yy
/ X9 n. y; Q, [( C( E$ s    yy
3 R* ?2 ?5 t1 H1 f+ z    zz 7 F: m- u( H; P
    6. while 语法以及流程图如下 7 @: F) I0 p4 {* ?
    │ FALSE
  Q) ~, J' L2 K" Z    while (condition) ┌—<condition>—┐
5 S2 _8 g0 L3 w. \4 Y8 f+ N$ C    do │ │TRUE │   D  m# n. [+ o  a6 b% Y
    commands │ commands │
& Q$ _: y2 N8 z0 \, W' `    done └————┘ │ ; G  H5 g  f4 H# g5 u: V, x: f
    ┌————┘
0 c4 N+ n9 R( @; E    │
% o  c$ v" W* ?! \# y3 ]    ┌———————————————┐
6 @% ^( k# e; @, }: q% h! P2 i    │number=0 │ : H! G( K8 b. l9 K
    │while (test $number -lt 10) │
4 `7 y9 j) w0 i! D  Z0 p' g    │ do │   Z3 A- G9 Y* u( E, f, p
    │ echo "$number\c" │ 8 b$ W) s$ ~+ p& a
    │ number=`expr $number + 1` │ 2 z, O: l' _5 j+ U3 f% I, }$ `! O
    │done │
# f/ l9 ?% C8 p    │echo │ 9 r( S4 r  v4 q4 f. c2 R4 V
    └———————————————┘ $ }. a5 F* ]2 R5 t! u/ R! Z
    结果如下:   r/ n8 C2 m# V" R* X9 h
    0123456789
, x3 v9 W( S; J' ?, U    7. until语法以及流程图如下
! ]$ V) K2 b+ b. [& ?' T    │ TRUE
0 d% G1 \( m7 O$ b* n    until (condition) ┌—<condition>—┐ ( i0 R7 E  R. I1 U9 s* |
    do │ │FALSE │ $ A* ?: ?( Q. _% P! p* |, `# w
    commands │ commands │ . i, J4 P" b$ C6 P
    done └————┘ │ / U! }/ o; X# R$ z5 h" U1 A
    ┌————┘
* y! V7 n! G3 T6 G    │
% q% f" Y# s* a( r    它和while 的不同只在於while 是在条件为真时执行回圈,而until 是在条件 为假时执行回圈。
7 Q5 F/ J# w6 e/ X1 h1 N    8. break及continue
: p; `; B7 a7 C3 ]' L    这两者是用於for, while, until 等回圈控制下。break 会跳至done後方执行 ,而continue会跳至done执行,继续执行回圈。 0 t$ |% K8 E* ~" u! L( u* D2 n
    9. case语法以及流程图如下
+ a! _4 s& f; v4 S# U/ E! S! H' {    │ TRUE
$ O, v, s+ _1 d) F2 [% g    case str in <str=pat1>————commands1—┐ + X( S* \$ H1 l
    pat1= commands1;; │FALSE TRUE │ ' F' q* N/ _. Z0 c/ z/ u& M' W
    pat2= commands2;; <str=pat2>————commands2—┤ ; p' w2 z1 U4 J- _* v# M% n" Z  o
    pat3= commands3;; │FALSE TRUE │ ; j: E, k3 Z3 s3 A4 U! X
    esac <str=pat3>————commands3—┤ ) f" \3 a$ |7 v6 Z+ n% A1 ~$ r
    │FALSE │ ! b1 v4 A: ~8 z  L) ?; ^+ @( K6 v
    ├————————————┘ $ M& {! q9 w7 w9 R( q
    │
' O! t& Z5 z$ u, l* d1 k6 a    而pat 除了可以指定一些确定的字串,也可以指定字串的集合,如下
: h9 Q9 O! {& v' d: D6 {1 Y    * 任意字串
. U, e- c& r9 }    ? 任意字元
9 r$ `/ [7 [; {# Y, a    [abc] a, b, 或c三字元其中之一 / ^  b6 u) t, Z4 j
    [a-n] 从a到n的任一字元
1 _; c# {2 E( ^1 @2 b    | 多重选择
& b- o1 p2 x  \6 c0 y/ E    ┌———————————————┐ + h5 i" O+ m/ X! t
    │echo 'Enter A, B, or C: \c' │
' z( ?+ o$ Y" F2 _; Q    │read letter │
2 x: G" q4 _# f( A    │case $letter in │
2 n9 G3 x( n% @, W3 t- z    │ A|a= echo 'You entered A.';;│ & z* o! F) e: K+ x2 Q% d) L
    │ B|b= echo 'You entered B.';;│
0 ]  X, _* B, S  v& a    │ C|c= echo 'You entered C.';;│ , y. I( @4 ~& v+ A; c
    │ *= echo 'Not A, B, or C';; │ 8 ?, h; W$ u+ Y* n. _0 l# h0 m
    │esac │
1 J0 Y: ^4 B$ v6 d# O' v, p3 f! g    └———————— - l' A7 i7 {' |) R
    Linux程式设计-11.Shell Script(bash)--(1)简介+ y: H% q+ c4 F% _- `. K5 E6 y' B
    众所皆知地,UNIX上以小工具着名,利用许多简单的小工具,来完成原本需要大量软体开发的工作,这一点特色,使得UNIX成为许多人心目中理想的系统平台。
/ l/ U% r# n, C4 e8 k- A5 R" s* R$ \9 t, Y    在众多的小工具中,Shell Script算得上是最基本、最强大、运用最广泛的一个。它运用围之广,不但从系统启动、程式编译、定期作业、上网连线,甚至安装整个Linux系统,都可以用它来完成。
7 A- J7 `  }0 I. }    因为Shell Script是利用您平日在使用的一些指令,将之组合起来,成为一个"程式"。如果您平日某些序列的指令下得特别频繁,便可以将这些指令组合起来,成为另一个新的指令。这样,不但可以简化并加速操作速度,甚至还可以乾脆自动定期执行,大大简化系统管理工作。 * K$ Y  \& B, Q9 f3 A& H
    --------------------------------------------------------------------------------
4 b* }! N8 O& I    Bash(GNU Bourne-Again SHell)是许多Linux平台的内定Shell,事实上,还有许多传统UNIX上用的Shell,像tcsh、csh、ash、bsh、ksh等等,Shell Script大致都类同,当您学会一种Shell以後,其它的Shell会很快就上手,大多数的时候,一个Shell Script通常可以在很多种Shell上使用。
' L) p* X$ h7 Q    这里我介绍您bash的使用方法。事实上,当您"man bash"时,就可以看到bash的说明书,不过对许多人来说,这份说明书犹如"无字天书"一样难懂。这份文件,主要资料来源为"man bash",我加上一些实际日常的应用例来说明。希望这样能让那些始终不得其门而入的人们,多多少少能有点概念。 ) N9 b9 V( Y7 E7 b. I
    Linux程式设计-11.Shell Script(bash)--(2)教学例
. e! N" p' n& N% M) g    Hello world" Shell Script
8 b4 x2 E& X+ D9 ^+ M/ k$ n# \1 j! R    照传统程式教学例,这一节介绍Shell Script的"Hello World"如何撰写。
& g% a% a- E' f8 I- F, C    -------------------------------------------------------------------------------- 7 f8 O1 i; O( J9 i6 H$ l! m
    #!/bin/sh , f& \! A6 e" }9 d
    # Filename : hello , P' \' Q" Y2 v+ S: n6 t8 k
    echo "Hello world!"
8 C9 G% C0 s6 U7 }+ @6 L    --------------------------------------------------------------------------------
! {  A3 D6 a6 y# I    大家应该会注意到第一行的"#!/bin/sh"。在UNIX下,所有的可执行Script,不管是那一种语言,其开头都是"#!",例如Perl是"#!/usr/bin/perl",tcl/tk是"#!/usr/bin/wish",看您要执行的Script程式位置在那里。您也可以用"#!/bin/bash"、"#!/bin/tcsh"等等,来指定使用特定的Shell。 $ {% N- I" C& I
    echo是个bash的内建指令。 + T. c; S1 J$ e% Q
    --------------------------------------------------------------------------------
5 S4 F$ ~: {0 S( V    接下来,执行hello这个script:
/ j! b4 q- R* O' \- n8 p    要执行一个Script的方式有很多种。 " T+ X6 Q. J( \! h# ^  w
    -------------------------------------------------------------------------------- 9 x9 Q6 O4 x1 G
    第一种 : 将hello这个档案的权限设定为可执行。
4 J6 \5 Z" c7 c. @; a: H    [foxman@foxman bash]# chmod 755 hello + F0 o: h) q9 v# b. b' Z. `: Z
    执行 $ s& G5 G7 y& V+ Q0 B, |. a4 U
    [foxman@foxman bash]# ./hello
% @0 E+ F0 U1 S: u7 X& T    hello world 0 ]. |* z) n* |2 W, [+ n6 j0 c
    --------------------------------------------------------------------------------
& a) m0 X, ^# O# |    第二种 : 使用bash内建指令"source"或"."。
/ V. Q1 I' a. j. |5 @    [foxman@foxman bash]# source hello 9 h$ ?- Q* L5 H" k/ |
    hello world ' G2 A0 x$ P1 g0 W
    或
5 V6 ^2 l+ x9 Z* m1 M2 i' J* S8 k    [foxman@foxman bash]# . hello - g2 w  N# ~. F1 I& I
    hello world # ]8 v  f( K+ s% p! o+ B. X# v$ `9 x
    --------------------------------------------------------------------------------
8 n( G- H* {$ y$ ]0 o    第三种 : 直接使用sh/bash/tcsh指令来执行。 ( o* b9 W. {( I$ y1 J/ K
    [foxman@foxman bash]# sh hello
$ U; {3 u, A8 a% G7 M    hello world $ n2 l  I9 I" C1 s
    或 0 K; |4 {, f* h% p3 d! Y: F. W$ }
    [foxman@foxman bash]# bash hello
% w: j4 r/ R% v    hello world
% f: m( l3 n) R) F    --------------------------------------------------------------------------------
7 y( H5 L6 ^9 }/ ?    Bash执行选项 * S& Q0 w) t& Z0 m3 _
    -------------------------------------------------------------------------------- 5 _/ ~! L% V6 M0 U: O/ t9 w% N
    -c string : 读取string来当命令。
" w6 @' K* W8 l+ O) q    -i : 互动介面。
; I; i, l; M- |- r    -s : 由stdin读取命令。
) r) v% P3 |4 Q) ]9 B    - : 取消往後选项的读取。
0 l! u/ g- y) h/ U% i3 L/ S    -norc : 不要读~/.bashrc来执行。
( G% T# {; E3 I3 B8 E    -noprofile : 不要读/etc/profile、~/.bash_profile、~/.bash_login、~/.profile等等来执行。
9 r. L0 t8 T# i2 d* t$ P. p0 H    -rcfile filename : 执行filename,而非~/.bashrc . t& b' ?$ Z" E, A
    -version : 显示版本。 ' `: A% ^7 K+ A( o, I. H0 c$ {! g
    -quiet : 启动时不要哩唆。
2 A, O; P7 t0 n5 q% q) }    -login : 确保bash是个login shell。 8 {# L4 n) m5 M$ F$ O, d) c
    -nobraceexpansion : 不要用curly brace expansion({}符号展开)。 - s! t- P6 b. d
    -nolineediting : 不用readline来读取命令列。 # U2 n- \9 G! q7 d: c) ^
    -posix : 改采Posix 1003.2标准。 $ l8 k* E8 g5 x! t
    Linux程式设计-11.Shell Script(bash)--(3)用於自动备份的Shell Script
+ y, U2 f8 ^6 G6 q* B( n3 y    一个用於自动备份的Shell Script 4 d9 E; M4 P# S4 [+ `- f4 q
    我们先前提到,可利用Shell Script搭配crond来作定期的工作。要作定期性的工作,在UNIX上,就是与crond的搭配运用。 1 x5 |9 {9 F, ?" i, n7 v0 c
    -------------------------------------------------------------------------------- % e4 _9 Y! ?8 J4 L: T
    首先我们先来研究如何对系统进行备份。 : N* O  ]) ]# x4 P- o
    要对系统进行备份,不外乎便是利用一些压缩工具。在许多UNIX系统上,tar及gzip是de facto的资料交换标准。我们经常可以看见一些tar.gz或tgz档,这些档案,被称为tarball。当然了,您也可以用bzip2、zip等等压缩工具来进行压缩,不必限定於gzip。但tar配合gzip是最普遍的,也是最方便的方式。 ' J2 [9 u2 F/ J
    要将我们想要的资料压缩起来,进行备份,可以结合tar及gzip一起进行。方式有很多种,最常用的指令是以下这一种: 3 ~) i! }6 _/ {/ m0 @# u5 @
    tar -c file/dir ... | gzip -9 > xxxx.tar.gz
. R" n) s4 N4 x6 ^# x+ x    您也可以分开来做:
# z. N6 I" R( B/ j$ Z; K6 g+ y8 G    tar -r file/dir ... -f xxxx.tar , s( {' W$ D! t) A
    gzip -9 xxxx.tar # f/ z/ H: ]% O$ ?
    或
! D1 f& L* \3 m8 h- J- U    tar -r file/dir ... -f xxxx.tar " j$ I; D' d! K
    gzip -9 xxxx.tar.gz 9 b' q; S! f" Q3 v% U, K6 |
    --------------------------------------------------------------------------------
5 @, j$ U& b4 N6 G) ~    在解过Linux下档案备份的基本知识後,我们来写一个将档案备份的Script。
% }) k; s, _- R$ d9 n. L# o    #!/bin/sh
  Z# x! h$ F' z" b* b    # Filename : backup
8 L9 n" b. z, Q; b4 ^    DIRS="/etc /var /your_directories_or_files" * ]6 e5 r1 v4 D9 Q+ f
    BACKUP="/tmp/backup.tgz" 6 l4 C9 D/ t1 S4 s% Q, ^
    tar -c $DIRS | gzip -9 > $BACKUP 2 q4 w, ]/ o& Y8 y
    其中DIRS放的是您要备份的档案及目录,BACKUP是您的备份档。可不要将/tmp放进DIRS中,那样做,您是在做备份的备份,可能将您的硬碟塞爆。
, d; l! r0 h4 f- E* j" ^    --------------------------------------------------------------------------------
: f2 G; s! N2 v: U0 @: H6 J1 F    接下来测试 / G8 j/ n' W6 ^* i  l3 B
    [foxman@foxman bash]# chmod 755 backup $ B8 |/ a! `6 h) G1 t
    [foxman@foxman bash]# ./backup 7 G: ]8 e: m* G% A
    执行完成後在/tmp就会有一个backup.tgz,里面储存了您重要的资料。您可用 9 [- L. ^. w" @4 M% X4 p: n0 h0 F
    gzip -dc /tmp/backup.tgz | tar -vt
: i( L$ _/ {7 p    或 1 T0 B5 b) ~" r
    tar vtfz /tmp/backup.tgz
. U& D, ~9 a6 ~* ~& \    来看看里面的档案列表。
6 V& I% C+ W  U8 |    要解开时,可用以下指令来完成复原:   p0 L( h3 D. x) O
    gzip -dc /tmp/backup.tgz | tar -xv
- w7 _* q7 W. \( ~& `3 c2 d    或 ; j. G4 X* P9 u9 f' g$ p
    tar xvfz /tmp/backup.tgz
" P* B, h2 q( _/ V. }% U    备份通常是仅备份系统通常最重要的部份,/etc可说是不可缺少的一部份。另外,看您系统中有那些重要的资料需要备份。通常来说,您没有必要备份/bin、/sbin、/usr/bin、/usr/sbin、/usr/X11R6/bin等等这些执行档目录。只要备份您重要的档案即可,别把整个硬碟备份,那是蛮呆的动作。 ( Q  @: g+ l. G" Y
    --------------------------------------------------------------------------------
2 _+ X5 `7 K: @) \" |    如果您有许多台机器,可利用其中一台任务较轻的内部网路主机,做为主要备份主机。将所有机器都自动执行备份,然後利用NFS/Coda/Samba等网路档案系统,将备份的资料放到该备份机器中,该机器则定时收取备份资料,然後您再由该机器中进行一次备份。 / z' O6 {4 M9 ~+ C, g" j
    这里是整个系统备份方案的图示。 + y* I, K' I* m* R
* }: E/ x3 Z% q  d0 ]
    在您进行之前,先解一下,系统中那些是要备份的,那些是不需要的。 ! B5 O" Y9 ], Z7 Q5 a. {, M* Y
    -------------------------------------------------------------------------------- + X. S$ P, c& W: q: K
    新的backup 4 p6 S8 K* e! z& H; w3 f2 u* a) b: ~+ ~
    #!/bin/sh * O7 ?  I1 b6 L
    HOSTNAME=`hostname`
* v3 Y' w1 {' [- C! ~    DIRS="/etc /var /your_important_directory" 2 a! ]+ o4 @  o) q6 Q3 ]
    BACKUP="/tmp/$HOSTNAME.tgz"
% }/ W% D0 ?9 q    NFS="/mnt/nfs" - b/ b( N; A$ a( J7 N) F
    tar -c $DIRS | gzip -9 > $BACKUP 9 p( T" t  }$ u$ L/ B5 ~
    mv -f $BACKUP $NFS
# @  g5 y2 s: X" f+ F    -------------------------------------------------------------------------------- 8 o8 w" p* C1 x8 {. k1 T
    备份主机内的Script : collect_backup 1 c/ r  t9 j1 z
    #!/bin/sh 9 S% [( r. v2 C' `  O  I
    NFS="/mnt/nfs" # C* V7 r9 [' @' G2 R: V
    BACKUP="/backup"
. y- p* `! D  V" o# M" X    mv -f $NFS/*.tgz $BACKUP : A+ L# U- U" `9 Z0 D

; G! P% [( d) I1 c0 P3 f) j0 h8 d    在此,您不能够将所有备份都直接放在/mnt/nfs,这是危险的。万一任一台机器不小心将/mnt/nfs所有内容删除,那麽备份就会消失。因此,您需要将/mnt/nfs移到一个只有该备份主机可存取的目录中。
/ |: e, u! L# T. G    --------------------------------------------------------------------------------
7 E+ H: v- p: w: f, B4 p+ f7 z    当这些个别的Script都测试好以後,接下来我们将他们放到crontab里面。找到您的crontab,它的位置可能在/var/spool/cron/crontabs/root、/etc/crontab、/var/cron/tabs/root。 : Y5 y7 |) \' J4 i# l- R0 M
    在crontab中选择以下之一加入(看您定期的时间):
3 i, a8 |. C6 Z7 a    Slackware : /var/spool/cron/crontabs/root * H$ U% R4 K/ X& ]
    01 * * * * /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每小时(太过火一点)
4 d6 X% O( }" r" o- t' G    30 16 * * * /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每日16:30,下班前备份
  d2 \  Q/ z) G: I/ x" q3 a5 T/ s- N    30 16 * * 0 /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每周一16:30
) k) j! D/ k& a1 @! m9 H2 c    0 5 1 * * /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每月一号5:0 / @4 R5 }9 q& b9 y% K
    RedHat/Debian : /etc/crontab ( w1 F$ W7 ]" ^: o- v  W9 M
    RedHat可直接将backup放入/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthly。或采用如上加入/etc/crontab的方式: / l) ^$ j/ v. R( u9 D7 x
    有关crontab的用法,可查"man 5 crontab",在此不详述。 6 \- Y& g8 X+ F
    备份主机的设定类同。 3 }& L0 E# x1 Q2 M' ^
    注意: 所有机器不要同时进行备份,否则网路会大塞车。备份主机收取备份的时间要设为最後,否则会收不到备份资料。您可以在实作後,将时间间隔调整一下。
& }& y0 a+ F9 S" ^  n! n    -------------------------------------------------------------------------------- 2 c, k- [/ p4 n4 q$ \
    看看,两个小小不到三行的Shell Script,配合cron这个定时工具。可以让原本需要耗时多个小时的人工备份工作,简化到不到十分钟。善用您的想像力,多加一点变化,可你让您的生活变得轻松异常,快乐悠哉。   _5 [" e: V7 V0 I3 @
    Linux程式设计-11.Shell Script(bash)--(4)档案系统检查
4 z  W' y# h2 i# }7 K     系统安全一向是大多数电脑用户关心的事,在UNIX系统中,最重视的事,即系统中有没有"木马"(Trojan horse)。不管Trojan horse如何放进来的,有一点始终会不变,即被放置木马的档案,其档案日期一定会被改变,甚至会有其它的状态改变。此外,许多状况下,系统会多出一些不知名的档案。因此,平日检查整个档案系统的状态是否有被改变,将所有状态有改变的档案,以及目前有那些程式正在执行,自动报告给系统管理员,是个避免坐上"木马"的良方。 , z/ ^. O1 {- s  t: v- a% \9 |
    -------------------------------------------------------------------------------- 3 E, {6 D7 }% l7 U8 R  W
    #!/bin/sh
. _4 }2 j. t' _% L9 D1 B    # Filename : whatever_you_name_it
0 J. u" @6 E9 ?9 a( z% l; I) G" N    DIRS="/etc /home /bin /sbin /usr/bin /usr/sbin /usr/local /var /your_directory"
+ Q" M# J6 f& ?% G. N    ADMIN="email@your.domain.com" ( T0 |2 j- B8 _6 p( Z- y
    FROM="admin@your.domain.com" % ?) t4 O) E. `- [% e
    # 写入Sendmail的标头
1 [! D' B. A- a3 r9 z    echo "Subject: $HOSTNAME filesystem check" > /tmp/today.mail
2 I1 V! X; Q4 z# v    echo "From: $FROM" >> /tmp/today.mail # F8 I' r" T* Q) N6 f( T* Q
    echo "To: $ADMIN" >> /tmp/today.mail 2 U0 e2 l% U5 S  L! b  d3 T( Q+ i0 H
    echo "This is filesystem report comes from $HOSTNAME" >> /tmp/today.mail
& g8 ~$ W5 b  c) y8 j    # 报告目前正在执行的程式
$ J: Y; ?5 [8 X7 h$ V. K5 k! c    ps axf >> /tmp/today.mail
/ F2 ?6 S- f5 J    # 档案系统检查 . i  p, F5 e# t
    echo "File System Check" >> /tmp/today.mail 8 P! _& V6 c) u$ {0 ^
    ls -alR $DIRS | gzip -9 > /tmp/today.gz 9 f1 m/ I+ F1 F5 n& c
    zdiff /tmp/today.gz /tmp/yesterday.gz >> /tmp/today.mail * v5 |1 ^) k" R
    mv -f /tmp/today.gz /tmp/yesterday.gz
  h: ^! L- ^; ?  d    # 寄出信件 . N0 w* a1 X% q1 o3 @% l
    sendmail -t 然後把它放到一个不显眼的地方去,让别人找不到。 : k0 ~7 _, `. |) s. n
    把它加入crontab中。 ( A3 G$ ?; [4 ^& A; a) ~
    30 7 * * * /full_check_script_path/whatever_you_name_it 1> /dev/null 2> /dev/null #上班前检查
. ]+ K- O. X& Q5 b0 N4 r$ T: N. Z    有些档案是固定会更动的,像/var/log/messages、/var/log/syslog、/dev/ttyX等等,不要太大惊小怪。  S3 P2 }1 Y3 }% e
9 h1 A1 I+ d; F: p
来源:网络.  还没有详细看.. 空下来了再仔细看.1 u' d( X$ y! L' M/ h- n: c/ z, b
, _, F. X+ e6 d9 D/ X* y( D- H4 C* Y2 z0 {! M2 C  ~+ W4 m# M1 [' Y4 H! i
参考文档:  这个文档也有做较详细的说明.

美国VPS、域名代购:http://tu8l.taobao.com

返回列表
Namecheap
Namecheap.com - Cheap domain name registration, renewal and transfers - Free SSL Certificates - Web Hosting
互联网安全