Shell编程 [收藏本页]
  • 作者:佚名 来源:不详 发布时间:2006-8-30 4:13:48
  • 在DOS中,你可能会从事一些例行的重覆性工作,此时你会将这些重覆性的命令写成批次档,只要执行这个批次档就等於执行这些命令。大家会问在UNIX中是否有批次处理这个东东,答案是有的。在UNIX中不只有如DOS的批次处理,它的功能比起DOS更强大,相对地也较复杂,已经和一般的高阶语言不相上下。在UNIX中大家都不叫做批次档,而叫做ShellScript。

    一般而言,ShellScript的地位和其它的可执行档(或命令)是完全相同的,只不过ShellScript是以文字档的方式储存,而非二进位档。而执行ShellScript时,必须有一个程式将其内容转成一道道的命令执行,而这个程式其实就是Shell,这也就是为什麽我们叫做ShellScript的原因(往後我们称为Script)。不同Shell的Script基本上会有一些差异,所以我们不能将写给Ashell的Script用Bshell执行。而在UNIX中大家最常使用BourneShell以及CShell,所以这堂课就介绍这两种Script的写法。

    将文字档设为可执行的ShellScript

    如果我们已经写好Script,如何将其设成可执行档呢?因为Script其实是一个可执行档,所以必须将其存取权设定成可执行。我们可以使用下列命令更改存取权:
    chmodu xfilename只有自己可以执行,其它人不能执行
    chmodug xfilename只有自己以及同一群可以执行,其它人不能执行
    chmod xfilename所有人都可以执行

    而我们如何指定使用那一个Shell来解释所写的Script呢?几种基本的指定方式如下所述:
    1.如果Script的第一个非空白字元不是"#",则它会使用BourneShell。
    2.如果Script的第一个非空白字元是"#"时,但不以"#!"开头时,则它会使用CShell。
    3.如果Script以"#!"开头,则"#!"後面所写的就是所使用的Shell,而且要将整个路径名称指出来。

    这里建议使用第三种方式指定Shell,以确保所执行的就是所要的。BourneShell的路径名称为/bin/sh,而CShell则为/bin/csh。


    1.使用BourneShell
    ┌——————————┐┌——————————┐
    │echoenterfilename││#!/bin/sh│
    │.│or│.│
    │.││.│
    │.││.│
    └——————————┘└——————————┘

    2.使用CShell
    ┌——————————┐┌——————————┐
    │#CShellScript││#!/bin/csh│
    │.││.│
    │.││.│
    │.││.│
    └——————————┘└——————————┘

    3.使用/etc/perl
    ┌——————————┐
    │#!/etc/perl│
    │.│
    │.│
    │.│
    └——————————┘

    除了在Script内指定所使用的Shell外,你也可以在命令列中强制指定。比如你要用CShell执行某个Script,你可以下这个命令:
    cshfilename

    此时的Script的存取权就不一定要为可执行档,其内部所指定的Shell也会无效,详细的情形後面会讨论。

    □Script的基本结构及观念

    Script是以行为单位,我们所写的Script会被分解成一行一行来执行。而每一行可以是命令、注解、或是流程控制指令等。如果某一行尚未完成,可以在行末加上"\",这个时候下一行的内容就会接到这一行的後面,成为同一行,如下

    ┌———————————┐
    │echoThemessageis\│
    │toolongsowehave\│
    │tosplititinto\│
    │severallines│
    └———————————┘

    当Script中出现"#"时,再它後面的同一行文字即为注解,Shell不会对其翻译。

    在Script中要执行一个命令的方法和在命令列中一样,你可以前景或背景执行,执行命令时也会需要设定一些环境变数。

    Script的流程控制和一般高阶语言的流程控制没有什麽两样,也和高阶语言一样有副程式。这些使得Script的功能更加强大。

    为了达到与高阶语言相同的效果,我们也可以在Script中设定变数,如此使Script成为一个名付其实的高阶语言。

    □BourneShell

    一、变数

    BourneShell的变数型态只有字串变数,所以要使用数值运算则必须靠外部命令达成目的。而其变数种类有下列几种:

    1.使用者变数

    这是最常使用的变数,我们可以任何不包含空白字元的字串来当做变数名称。设定变数值时则用下列方式:
    var=string

    取用变数时则在变数名称前加上一"$"号。


    ┌———————┐
    │name=Tom│
    │echoname│
    │echo$name│
    └———————┘
    结果如下:
    name
    Tom

    2.系统变数(环境变数)

    和使用者变数相似,只不过此种变数会将其值传给其所执行的命令。要将一使用者变数设定为系统变数,只要加上:
    exportvar

    ┌———————┐
    │name=Tom│
    │exportname│
    └———————┘

    以下是使用者一进入系统之後就已设定好的系统变数:
    $HOME使用者自己的目录
    $PATH执行命令时所搜寻的目录
    $TZ时区
    $MAILCHECK每隔多少秒检查是否有新的信件
    $PS1在命令列时的提示号
    $PS2当命令尚未打完时,Shell要求再输入时的提示号
    $MANPATHman指令的搜寻路径

    3.唯读的使用者变数

    和使用者变数相似,只不过这些变数不能被改变。要将使用者变数设成唯读的,只要加上:
    readonlyvar

    而若只打readonly则会列出所有唯读的变数。还有一点,系统变数不可以设定成唯读的。

    ┌———————┐
    │name=Tom│
    │readonlyname│
    │echo$name│
    │name=John│
    │readonly│
    └———————┘

    结果如下:
    Tom
    name:isreadonly
    readonlyname
    readonly......

    4.特殊变数

    有些变数是一开始执行Script时就会设定,并且不以加以修改,但我们不叫它唯读的系统变数,而叫它特殊变数(有些书会叫它唯读的系统变数),因为这些变数是一执行程式时就有了,况且使用者无法将一般的系统变数设定成唯读的。以下是一些等殊变数:
    $0这个程式的执行名字
    $n这个程式的第n个参数值,n=1..9
    $*这个程式的所有参数
    $#这个程式的参数个数
    $$这个程式的PID
    $!执行上一个背景指令的PID
    $?执行上一个指令的返回值

    当你执行这个程式时的参数数目超过9个时,我们可以使用shift命令将参数往前移一格,如此即可使用第10个以後的参数。除此之外,吾人可以用set命令改变$n及$*,方法如下:
    setstring

    如此$*的值即为string,而分解後则会放入$n。如果set命令後面没有参数,则会列出所有已经设定的变数以及其值。

    档名:ex1参数:thisisatest

    ┌———————————┐
    │echoFilename:$0│
    │echoArguments:$*│
    │echoNo.ofargs.:$#│
    │echo2ndarg.:$2│
    │shift│
    │echoNo.ofargs.:$#│
    │echo2ndarg.:$2│
    │sethello,everyone│
    │echoArguments:$*│
    │echo2ndarg.:$2│
    └———————————┘
    结果如下:
    Filename:ex1
    Arguments:thisisatest
    No.ofargs.:4
    2ndarg.:is
    No.ofargs.:3
    2ndarg.:a
    Arguments:hello,everyone
    2ndarg.:everyone

    值得一提的是,当你想从键盘输入一变数值时,你可以使用下面的命令:
    readvar1var2.....

    这时read会将一个字分给一个变数。如果输入的字比变数还多,最後一个变数会将剩下的字当成其值。如果输入的字比变数还少,则後面的变数会设成空字串。如果需要处理数值运算,我们可以使用expr命令。其参数及输出列於附录A。

    二、执行命令

    在BourneShell中有五种方法执行一个命令,而这五种方式所产生的果有些许的不同。

    1.直接下命令
    这个方式和在命令列中直接下命令的效果一样。

    2.使用sh命令
    shcommand
    这个档案必须是BourneShell的Script,但这个档案并不一定要设成可执行。除此之外和直接下命令的方式一样。

    3.使用"."命令
    .command

    这时和使用sh命令相似,只不过它不像sh一般会产生新的process,相反地,它会在原有的process下完成工作。

    4.使用exec命令
    execcommand
    此时这个Script将会被所执行的命令所取代。当这个命令执行完毕之後,这个Script也会随之结束。

    5.使用命令替换
    这是一个相当有用的方法。如果想要使某个命令的输出成为另一个命令的参数时,就一定要使用这个方法。我们将命令列於两个"`"号之间,而Shell会以这个命令执行後的输出结果代替这个命令以及两个"`"符号。

    str='Currentdirectoryis'`pwd`
    echo$str
    结果如下:
    Currentdirectoryis/users/cc/mgtsai
    这个意思是pwd这个命令输出"/users/cc/mgtsai",而後整个字串代替原来的`pwd`设定str变数,所以str变数的内容则会有pwd命令的输出。

    number=`expr$number 1`
    这就是先前所提要作数值运算的方法,基本上expr命令只将运算式解,而後输出到标准输出上。如果要将某变数设定成其值,非得靠命令替换的方式不可。这个例子是将number变数的值加1後再存回number变数。

    三、流程控制

    在介绍流程控制之前,我们先来看看test命令。test命令的参数是条件判断式,当条件为真时则传回非零值,而条件为伪时则传回零。在所有的流程控制都必须用到test命令来判断真伪。而test命令的使用方法则列於附录B。

    test$#=0

    如果执行这个程式没有参数时,会传回非零值代表"$#=0"这个条件成立。反之则会传回零。

    以下介绍各种流程控制:

    1.ifthen语法以及流程图如下

    │FALSE
    if(condition)<condition>—┐
    then│TRUE│
    then-commandsthen-commands│
    fi├————┘



    condition是一个test命令。往後所介绍的各种流程中的condition都是test命令。
    档名:chkarg

    ┌———————————┐
    │if(test$#!=0)│
    │then│
    │echoArg1:$1│
    │fi│
    └———————————┘
    $chkargHello
    Arg1:Hello
    $chkarg
    $

    2.ifthenelse语法以及流程图如下

    │FALSE
    if(condition)<condition>—————┐
    then│TRUE│
    then-commandsthen-commandselse-commands
    else├————————┘
    else-commands│
    fi

    3.ifthenelif语法以及流程图如下

    │FALSE
    if(condition1)<condition1>—┐
    then│TRUE│FALSE
    commands1commands1<condition2>—┐
    elif(condition2)││TRUE│
    then│commands2commands3
    commands2├—————┴————┘
    else│
    commands3

    commands3
    fi


    echo'word1:\c'
    readword1
    echo'word2:\c'
    readword2
    echo'word3:\c'
    readword3
    if(test"$word1"="$word2"-a"$word2"="$word3")
    then
    echo'Match:words1,2,&3'
    elif(test"$word1"="$word2")
    then
    echo'Match:words1&2'
    elif(test"$word1"="$word3")
    then
    echo'Match:words1&3'
    elif(test"$word2"="$word3")
    then
    echo'Match:words2&3'
    else
    echo'Nomatch'
    fi

    4.forin语法以及流程图如下

    │FALSE
    forvarinarg-list┌—<arg-list还有东西吗?>—┐
    do││TRUE│
    commands│从arg-list取得一项│
    done│放到变数var│
    │││
    │commands│
    └——————┘│
    ┌———————————┐┌—————┘
    │forainxxyyzz││
    │do│
    │echo$a│
    │done│
    └———————————┘
    结果如下:
    xx
    yy

    yy
    zz

    5.for语法以及流程图如下

    │FALSE
    forvar┌—<参数中还有东西吗?>—┐
    do││TRUE│
    commands│从参数中取得一项│
    done│放到变数var│
    │││
    │commands│
    └—————┘│
    档名:lstarg┌—————┘
    ┌———————————┐│
    │fora│
    │do│
    │echo$a│
    │done│
    └———————————┘
    $lstargxxyyzz
    xx
    yy

    yy
    zz

    6.while语法以及流程图如下


    │FALSE
    while(condition)┌—<condition>—┐
    do││TRUE│
    commands│commands│
    done└————┘│
    ┌————┘


    ┌———————————————┐
    │number=0│
    │while(test$number-lt10)│
    │do│
    │echo"$number\c"│
    │number=`expr$number 1`│
    │done│
    │echo│
    └———————————————┘
    结果如下:
    0123456789

    7.until语法以及流程图如下


    │TRUE
    until(condition)┌—<condition>—┐
    do││FALSE│
    commands│commands│
    done└————┘│
    ┌————┘


    它和while的不同只在於while是在条件为真时执行回圈,而until是在条件为假时执行回圈。

    8.break及continue
    这两者是用於for,while,until等回圈控制下。break会跳至done後方执行,而continue会跳至done执行,继续执行回圈。

    9.case语法以及流程图如下

    │TRUE
    casestrin<str=pat1>————commands1—┐
    pat1)commands1;;│FALSETRUE│
    pat2)commands2;;<str=pat2>————commands2—┤
    pat3)commands3;;│FALSETRUE│
    esac<str=pat3>————commands3—┤
    │FALSE│
    ├————————————┘


    而pat除了可以指定一些确定的字串,也可以指定字串的集合,如下
    *任意字串
    ?任意字元
    [abc]a,b,或c三字元其中之一
    [a-n]从a到n的任一字元
    |多重选择

    ┌———————————————┐
    │echo'EnterA,B,orC:\c'│
    │readletter│
    │case$letterin│
    │A|a)echo'YouenteredA.';;│
    │B|b)echo'YouenteredB.';;│
    │C|c)echo'YouenteredC.';;│
    │*)echo'NotA,B,orC';;│
    │esac│
    └————————
  • [] [返回上一页] [打 印] [收 藏]
  • 上一篇教程:赶走一些你不希望进入的用户 下一篇教程:Bash中的特殊字符
Copyright © 2003-2008 站长助手 www.web162.com
辽ICP备05001760号 网络实名:站长助手 转载本站原创教程请注名来源于本站
力倡站长资源文化,崇尚互联共享,做中国最好站长网站,为中国网站提供动力!
始建于2003-3-1 8:10 中国首都·北京 辽宁(分站)
主资源渠道辽宁电信分公司服务器组及带宽!