zoukankan      html  css  js  c++  java
  • 转载几篇有用的文章

    Unix系列shell程序编写(中)

    来源:转载 (2006-05-25 11:28:38)

    3>在Shell中使用数据变量

      用户可以在Shell中使用数据变量,例如ba.sh程序:

        
    QUOTE:
    cd/usr/icewalk
        ls|cpio -o > /dev/fd0

      该程序中要备份的目录为一常量,即该程序只能用来备份一个目录。若在该程序中使用变量,则会使其更通用:

        
    QUOTE:
    workdir=$1
        cd $workdir
        ls * |cpio -o > /dev/fd0

      通过这一改变,用户可以使用程序备份变量$workdir指定的目录。例如我们要备份/home/www的内容,只要运行ba.sh /home/www即可实现。(若不明白 $1,下面将详细介绍shell参数的传递,$1代表本sh程序-ba.sh的第一个参数)

      4>在Shell程序中加上注释

      为了增加程序的可读性,我们提倡加入注释。在Shell程序中注释将以"#"号开始。当Shell解释到"#"时,会认为从"#"号起一直到该行行尾为注释。

      5>对Shell变量进行算术运算

      高级语言中变量是具有类型的,即变量将被限制为某一数据类型,如整数或字符类型。Shell变量通常按字符进行存储,为了对Shell变量进行算术运算,必须使用expr命令。

      expr命令将把一个算术表达式作为参数,通常形式如下:

        expr [数字] [操作符] [数字]

      由于Shell是按字符形式存储变量的,所以用户必须保证参加算术运算的操作数必须为数值。下面是有效的算术操作符:

        +   两个整数相加
        -   第一个数减去第二个数
        *   两整数相乘
        /   第一个整数除以第二个整数
        %   两整数相除,取余数
      例如:
        $expr 2 + 1
         结果显示:3
        $expr 5 - 3
         结果显示:2

    若expr的一个参数是变量,那么在表达式计算之前用变量值替换变量名。
        $int=3
        $expr $int + 4
        结果显示:7
      用户不能单纯使用"*"做乘法,若输入:
        $expr 4*5
      系统将会报错,因为Shell看到"*"将会首先进行文件名替换。正确形式为:
        $expr 4 \* 5
         结果显示:20
      多个算术表达式可以组合在一起,例如:
        $expr 5 + 7 / 3
        结果显示:7
      运算次序是先乘除后加减,若要改变运算次序,必须使用"`"号,如:
        $int=`expr 5 + 7`
        $expr $int/3
         结果显示:4
        或者:
        $expr `expr 5+7`/3
        结果显示:4

      6>向Shell程序传递参数

      一个程序可以使用两种方法获得输入数据。一是执行时使用参数。另一种方法是交互式地获得数据。vi编辑程序可以通过交互式的方法获得数据,而ls和expr则从参数中取得数据。以上两种方法Shell程序都可以使用。在"交互式读入数据"一节中将介绍Shell程序通过交互式的方法获得参数。

      通过命令行给Shell程序传递参数可以扩大程序的用途。以前面提到的ba.sh程序为例:
      $cat >re.sh
      cd $workdir
      cpio -i < /dev/fd0
      ^d

      程序re.sh恢复了ba.sh程序备份的所有文件。若只从软盘上恢复一个指定的文件,可以用该文件名作为参数,传递给Shell程序re.sh:

      程序改写如下:
      
    QUOTE:
    $cat >re2.sh
      cd $workdir
      cpio -i $1 < /dev/fd0
      ^d

      用户可以指定要恢复的文件,例如fname

      $re2.sh fname

    此时文件fname作为第一个位置参数传递给re2.sh,re2.sh的缺点是要恢复两个或多个文件要重复运行,我们可以用$*变量传递不确定的参数给程序:

      
    QUOTE:
    $cat >re3.sh
      cd $workdir
      cpio -i $* < /dev/fd0
      ^d

      我们就可以恢复多个文件,例如fname1,fname2,fname3
      $re3.sh fname1 fname2 fname3
      (以上程序re.sh,re2.sh,re3.sh,假设用户已经chmod了可执行权利)

      因为没有赋值的变量可以作为NULL看待,所以若是程序re3.sh在执行时候没赋予参数,那么一个空值将被插入到cpio命令中。该命令将恢复所有保存的文件。

    条件判断语句

      条件判断语句是程序设计语言中十分重要的语句,该语句的含义是当某一条件满足时,执行指定的一组命令。

    1>if - then语句

      
    QUOTE:
    格式: if command1
         then
           command2
           command3
         fi      ---(if 语句结束)
           command4

      每个程序或命令执行结束后都有一个返回的状态,用户可以用Shell变量$?获得这一状态。if语句检查前面命令执行的返回状态,若该命令成功执行,那么在then和fi之间的命令都将被执行。在上面的命令序列中,command1和command4总要执行。若command1成功执行,command2和command3也将执行。

      请看下面程序:
        
    QUOTE:
    #unload -program to backup and remove files
        cd $1
        ls -a | cpio -o > /dev/mnt0
        rm *

      该程序在备份资料后,删除档案,但当cpio命令不能成功执行时,rm命令还是把资料删除了,我们可不希望这样,为了避免此情况,可以用if - then语句:
        #--卸载和判断删除程序

        
    QUOTE:
    cd $1
        if ls -a | cpio > /dev/mnt0
        then
          rm *
        fi

      上面程序在cpio执行成功后才删除档案

    同时,若执行没有成功,我们希望得到提示,sh中的echo命令可以向用户显示消息,并显示后换行,上面程序可以写成:
         #--卸载和判断删除程序
        cd $1
        if ls -a | cpio > /dev/mnt0
        then
          echo "正删除文件资料... ..."
          rm *
        fi

      echo命令可以使用一些特殊的逃逸字符进行格式化输出,下面是这些字符及其含义:

        \b  Backspace
        \c  显示后不换行
        \f  在终端上屏幕的开始处显示
        \n  换行
        \r  回车
        \t  制表符
        \v  垂直制表符
        \   反斜框
        \0nnn 用1,2或3位8进制整数表示一个ASCII码字符

    2>if - then - else语句

      不用多说它的作用,别的高级语言中都有,格式为:
      
    QUOTE:
    if command1
      then
        command2
        command3
      else
        command4
        command5
      fi

      在此结构中,command1中是先执行,当command1成功执行时,将执行command2和command3,否则执行command4和command5

      注意看下面程序:
        #备份程序
        cd $1
        if ls -a |cpio -o > /dev/mnt0
        then
          echo "删除源资料... ..."
          rm *
        else
          echo "磁带备份失败!"
        fi

    3>test命令进行条件测试

      if语句可以通过测试命令执行的返回状态来控制命令的执行,若要测试其他条件,在bsh中可以使用test命令。该命令检测某一条件,当条件为真时返回0,否则返回非0值。test命令可以使Shell程序中的if语句象其他程序语言中的条件判断语句一样,具有很强的功能。

      test命令的使用方法为:
        test condition
      可测试的条件分为4类:
      1)测试两个字符串之间的关系。
      2)测试两个整数之间关系。
      3)测试文件是否存在或是否具有某种状态或属性。
      4)测试多个条件的与(and)或(or)组合。

    1、条件语句>>test语句

    1>测试字符串间的关系

      bsh把所有的命令行和变量都看作字符串。一些命令如expr和test可以把字符当作数字进行操作。

      同样任何数字也可以作为字符串进行操作。

      用户可以比较两个字符串相等或不等,也可以测试一个串是否赋了值。有关串的操作符如下:
        str1 = str2      当两个串有相同内容、长度时为真
        str1 != str2      当串str1和str2不等时为真
        -n str1        当串的长度大于0时为真(串非空)
        -z str1        当串的长度为0时为真(空串)
        str1         当串str1为非空时为真

      不但Shell程序可以使用test进行条件判断,test命令也可以独立执行,如:

        $str1=abcd
        $test $str1 = abcd
        $echo $?
        结果显示:0

    与上例中第一行赋值语句中的等号不同,test命令中的等号两边必须要有空格。本例test命令共有3个参数。注意两个串相等必须是长度和内容都相等。

        $str1="abcd "
        $test "$str1" = abcd
        $echo $?
        结果显示:1

      上面str1包含5个字符,其中最后一个为空格符。而test命令中的另一个串只有4个字符,所以两串不等,test返回1。

      不带任何操作符和使用-n操作符测试一个串结果是一样的,例如:

        $str1=abce
        $test $str1
        $echo $?
        结果显示:0    
        $test -n $str1
        $echo $?
        结果显示:0

      但是,上面两条命令也有一点差别,反映出了使用test命令潜在的问题,请看下例:

        $str1="   "
        $test $str1
        $echo $?
        结果显示:1
        $test -n "$str1"
        $echo $?
        结果显示:0
        $test -n $str1
        结果显示:test:argument expected

      上例中,第一次测试为假因为Shell在执行命令行之前首先要进行变量替换,即把$str1换成空格,然后shell又将命令行上的空格删除,故test命令测试到的为空串。而在第二次测试中,变量替换后空格位于括号内,故不会被删除,test测试到的是一个包含空格的串,在第三次测试中,shell把空格删除,只把-n传个test命令,所以显示参数错。

    2>测试两个整数之间关系

      test命令与expr命令一样,也可以把字符转变成整数,然后对其操作。test命令对两个数进行比较,使用的操作符如下:

        int1 -eq int2    两数相等为真
        int1 -ne int2    两数不等为真
        int1 -gt int2    int1大于int2为真
        int1 -ge int2    int1大于等于int2为真
        int1 -lt int2    int1小于int2为真
        int1 -le int2    int1小于等于int2为真

      下面的例子反映了字符串比较与数字比较的不同:

        $str1=1234
        $str2=01234
        $test $str1 = $str2
        $echo $?
        结果显示:1
        $test $str1 -eq $str2
        $echo $?
        结果显示:0

    3>有关文件的测试

      使用test进行的第三类测试是测试文件的状态,用户可以测试文件是否存在,是否可写以及其他文件属性。下面是文件测试时使用的选项。注意只有文件存在时,才有可能为真。

      -r file     用户可读为真
      -w file     用户可写为真
      -x file     用户可执行为真
      -f file     文件为正规文件为真
      -d file     文件为目录为真
      -c file     文件为字符特殊文件为真
      -b file     文件为块特殊文件为真
      -s file     文件大小非0时为真
      -t file     当文件描述符(默认为1)指定的设备为终端时为真
    4>复杂的条件测试(and 、or 、not)
      -a         与
      -o        或
      !        非
      就是组合条件了,任何高级语言中都有的(NOT 、AND 、OR),例如:
        $test -r em.null -a -s em.null
        $echo $?
        结果显示:1
        说明了em.null并不是可读并且非空的文件

    5>另一种执行test的方法

      bsh中还有另一种执行test命令的方法,就是把测试条件放到一对[ ]中,例如:
        $int1=4
        $[ $int1 -gt 2 ]
        $echo $?
        结果显示:0

    要注意在[ 的后面和 ]符号的前面要有一个空格。
      下面我们用test命令写个简单但比较完善的程序:

        #-- 备份程序
      
        #-- 检查参数
        if [ $# -ne 1 ]
        then

          echo "请在程序名后面指出要备份文件所在目录!"
          exit 1
        fi
        #-- 检查目录名是否有效
        if [ !-d "$1" ]
        then
          echo "$1 不是一个目录!"
          exit 2
        fi
        cd $1
        ls -a | cpio -o >/dev/mnt0
        if [ $? -eq 0 ]
        then
          rm *
        else
          echo "cpio执行不成功!备份失败..."
          exit 3
        fi

    6>空命令

      在Bsh中用 : 代表空命令,就是充个数,什么都不做

    7>嵌套if语句和elif结构

      检查条件1
      A:当条件1为真,则执行一部分操作
      B:若条件1为假,检查条件2
        1)若条件2为真,执行另外一部分操作
        2)若条件2为假,检查条件3
        3)若条件3为真,执行其他一部分操作
      语法如下:
        if command
        then
          command
        else
          if command
          then
            command
          else
            if command
            then
              command
            fi
          fi
        fi

    8>elif语句

      嵌套if语句有时会给用户带来混乱,特别是什么时候fi语句很难判断。因此Bourne Shell又提供了elif语句。elif是else-if的缩写,它表示是if语句的继续。格式为:

        if command
        then
          command
        elif command
        then
          command
        elif command
        then
          command
        fi

      上面介绍的嵌套if语句和elif语句完成相同的功能,用户可以根据自己的喜好选择一种使用。

    9>case语句

      前面说的elif语句替代if-then-else语句,但有时在编程时还会遇到对同一变量进行多次的测试,该情况可以用多个elif语句实现,但还有一种更简单的方法就是用case语句。

      case语句不但取代了多个elif和then语句,还可以用变量值对多个模式进行匹配,当某个模式与变量值匹配后,其后的一系列命令将被执行,下面是case语句使用的语句。

      case value in
       pattem 1)
        command
        command;;
       pattem 2)
        command
        command;;
       ....
       pattem)
        command;
      esac

      case语句只执行其中的一组命令,当变量值与多个模式相匹配时,只有第一个匹配的模式对应的命令被执行。";;"表示该模式对应的命令部分程序。

      通过学习下面的read语句,我们们再举例子说明case语句的用法。

    10>read语句

      Shell程序不但可以通过命令行参数得到输入数据,还可以使用read命令提示用户输入数据,其语法格式为:

      read var1 var2... ...varn

    当Bsh遇到一个read语句时,在标准输入文件中读取数据直到一个换行符。此时Shell在解释输入行时,不进行文件名或变量的替换,只是简单地删除多余的空格。然后Shell将输入行的第一个字的内容给变量1,第二个给变量2,直到所有变量都赋上值或是输入行为空。若输入行中字的个数超过变量个数,Shell将把输入行中剩余的所有字的内容都赋给最后一个变量。当变量个数多于输入行字的个数时候,多于的变量将赋一个空值。输入行的每一个字是由空格分隔的一个字母和数字组成的字符串。

      $read var1 var2 var3
        输入:Hello my friend
      
      $echo $var1 $var2 $var3
        结果显示:Hello my friend
      $echo $var2
        结果显示:my

    下面用个read和case的例子结束本部分的学习:

      
    QUOTE:
    #--交互式备份,恢复程序
      echo "输入要备份文件所在目录:\c"
      read WORKDIR
      if [ !-d $WORKDIR ]
      then
        echo "Sorry,$WORKDIR is not a directory"
        exit 1
      fi
      cd $WORKDIR
      echo "输入选择:"
      echo _
      echo "1.恢复到 $WORKDIR"
      echo "2.备份 $WORKDIR"
      echo "0.退出"
      echo
      echo "\c"
      read CHOICE
      case "$CHOICE" in
       1)echo "恢复中... ..."
        cpio -i < /dev/mnt0;;
       2)echo "备份中... ..."
        ls | cpio -o > /dev/mnt0;;
       0)exit 1
       *)exit 1
      esac
      if [ $? -ne 0 ]
      then
       echo "程序运行中出现错误!"
      else
       echo "操作成功!"
    fi

     
     
      在上面代码中,"*"定义了其他模式下不匹配时的默认操作。

    循环语句

      前面介绍的程序和所学的语句都是从头到尾成一条主线下来,或是成分支结构,在日常管理UNIX的过程中,经常要重复的做一些操作,处理批量的问题,这就涉及到了循环结构,同高级语言相似,UNIX的Shell也提供了强大的循环处理语句。

      Bsh语言中有三种循环语句-while循环、until循环、for循环,下面通过具体的例子分别介绍这三种结构。

    While循环

      在while循环语句中,当某一条件为真时,执行指定的命令。语句的结构如下:

    while command
    do
      command
      command
      … …
    done

    示例代码如下:

    #测试while循环小程序

    x_t=1
      while [ $x_t -lt 5 ]
      do
         mm=` expr $x_t \* $int `  #注意"\"的作用
         echo "$mm"
         x_t=` expr $x_t + 1 `   #注意expr的用法
      done
      echo "THE WHILE IS END!\n"

    程序的执行结果如下:
    1
    4
    9
    16
    THE WHILE IS END

      在上述程序中,当变量x_t的值小于5的时候,执行while循环中的语句。在第五次循环时, [ $x_t-lt5]命令返回非零值,于是程序执行done后面的代码。
    现在利用while循环,可以改进我们早些时候用的备份数据的例子,当用户指定的目录备份完毕后,使用while循环使程序执行一次可以备份多个用户指定的目录。代码如下:

    echo "欢迎使用备份小程序"

      ANS=Y
      while [ $ANS = Y -o $ANS = y ]
      do
        echo _
        #读目录名
        echo "输入要备份的目录名:\c"
        read DIR
        if [ ! -d $DIR ]
        then
            echo "$DIR不是一个目录!"
            exit 1
        fi
        cd $DIR
        echo "请选择:"
        echo _
        echo "1 恢复数据到 $DIR"
        echo "2 备份$DIR的数据"
        echo
        echo "请选择:\c"
        read CHOICE
        case "$CHOICE" in
           1) echo "恢复中… …"
            cpio -i        2) echo "备份中… …"
            cpio -o >/dev/rmt0;;
           *) echo "选择无效"
        esac
        if [ $? -ne 0 ]
        then
           echo "cpio执行过程中出现问题"
           exit 2
        fi
        echo "继续别的目录吗?(Y/y)\c"
        read ANS
      done

      在程序开始,我们给变量ANS符值为Y,根据whlie的判断条件,程序进入while循环,执行do-done中的语句,每次循环都要求用户输入ANS的值用来判断是否进行下次重复执行do-done中的语句。如果用户输入的条件不满足while语句条件,循环结束,程序执行done后面的语句。
    (http://www.fanqiang.com)



  • 相关阅读:
    使用javap分析Java的字符串操作
    使用javap深入理解Java整型常量和整型变量的区别
    分享一个WebGL开发的网站-用JavaScript + WebGL开发3D模型
    Java动态代理之InvocationHandler最简单的入门教程
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
  • 原文地址:https://www.cnblogs.com/mogu/p/1505023.html
Copyright © 2011-2022 走看看