Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21600
  • 博文数量: 13
  • 博客积分: 325
  • 博客等级: 一等列兵
  • 技术积分: 120
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-28 14:33
文章分类

全部博文(13)

文章存档

2012年(13)

分类: LINUX

2012-10-25 15:53:58

    Bash Shell Script可以由许多命令组成。每一个命令执行后,都会传回一个结束状态值,如果执行成功,传回0,,如果执行失败,则传回非0值
    Bash的内置变量$?,用来存储每个命令执行后传回的状态值。例如

  1. #ls -l /
  2.  ...
  3. #echo $?
  4. 0

1、if 语法

    if条件判断的完整语法结构如下:
  1. if 条件测试1; then
  2.    命令区域1
  3. elif 条件测试2; then
  4.    命令区域2
  5. ...
  6. else
  7.    命令区域3
  8. fi
    例如,测试一个目录是否存在可以用以下代码:

  1. if [ -d /root/temp ]; then
  2.   echo '/root/temp exist'
  3. else
  4.   echo '/root/temp not exist'
  5. fi
    其中,行1用[]做条件测试,-d会检测/root/tempz这个目录是否存在。

    再比如,“检查某个账号是否存在”,可以写为:

  1. if grep -q ^testuser /etc/passwd; then
  2.    echo 'testuser exist'
  3. fi
    其中,行1使用grep命令寻找 /etc/passwd 文件中是否有以testuser这个关键词出现在行首(以^表示),如果有,表示该账号存在。选项 -q 表示不显示,只借助 $? 来传回执行结果。

  
 2、条件测试的写法
     
    (2-1)执行某一命令的结果
     
  1. #!/bin/bash
  2. if ! grep -q "rm" test.sh; then
  3.   echo "not find"
  4. else
  5.   echo "find rm command"
  6. fi
      其中,!命令,表示传回某一命令执行结果的相反值。需要注意的是,!和命令之间要有空格。
   
    (2-2)使用复合命令:((算式))
     (( ))是Bash的复合命令,内置算式。如果算式结果不为0,则传回真值,否则传回假值。它的意义等同于:let "算式"

  1. #!/bin/bash
  2. declare -i a b
  3. a=$1;b=$2
  4. if ((a
  5.    echo "$a less than $b"     
  6. else
  7.    echo "$a less than $b"
  8. fi
    其中,行3是声明a、b都是整数。

    (2-3)使用Bash关键词 '[['、‘]]’组成的式子:[[ 判断式 ]]
     判断式传回0为真,非0为假。注意,[[的后面和]]的前面,都只要要有一个以上的空格符才行。

  1. #!/bin/bash
  2. if [[ str > xyz ]]; then
  3.    echo "字符串str比较大"
  4. else
  5.    echo "字符串str比较小"
  6. fi
    本例的执行结果为,显示“字符串str比较小”。

    (2-4)使用内置命令:test 判断式

  1. #!/bin/bash
  2. if test "str" \> "xyz"; then
  3.    echo "字符串str比较大"
  4. else
  5.    echo " 字符串str比较小"
  6. fi
     需要注意的是,大于号>对Bash而言是特殊符号,需要用\予以转义。

    (2-5)使用内置命令:[]
      其形式为:[ 判断式 ]
      []和test的用法是相同的,两者可以改写互换。需要注意两边有空格。

  1. #!/bin/bash
  2. if [ "str" \> "xyz" ]; then    #等价于 if test "str" \> "xyz"; then
  3.    echo "字符串str比较大"
  4. else
  5.    echo " 字符串str比较小"
  6. fi
     (2-6)使用-a,-o进行逻辑组合
     
  1. [ -r filename1 -a -x filename1 ]
   上行,如果filename1可读且可以执行,则为真。 -a即为“且”之意.


  1. [ -r filename2 -o -x filename2 ]
   上行,如果filename2可读或可以执行,则为真。 -o即为“或”之意.

   (2-7)使用&&和||
    &&称为逻辑的AND,形式为:command1 && command2 ,其运作方式是:如果command1 执行结果为真,才会执行command2。如果两者皆为真,则传回真值0,否者传回假值1。
     ||称为逻辑的OR,形式为:command1 || command2 ,其运作方式是:如果command1 执行结果为假,才会执行command2。如果两个之中有一个是真的,则传回真值0,否者传回假值1。
     &&和||经常拿来当做是一种隐形的if语法。

  1. [ -z $PS1 ] && return
  2. #等价形式为
  3. if [ -z $PS1 ]; then
  4.    return
  5. fi
      这段代码的意思是:先判断$PS1变量值是否为空,如果是就执行return命令,由子shell返回到父shell,这等于是结束执行该Script。

    凡是形如“[ 判断式 ] && 指令”的形式,都可以视为一种隐形的if-then语法。&&和||合用,也可以有if-then-else的效果,例如:

  1. [ -n ${DEBUG:-} ] && set -v || set v
     这行程序代码,使用-n测试变量DEBUG是否有设为非空值,如果有,就表示要进行排错,接着执行&&的下一条指令:set -v;如果无,则不进行排错,而改为执行||的下一条指令:set v,它会把显示程序代码的功能关闭。
    本例的等价if语法形式如下:

  1. if [ -n ${DEBUG:-} ]; then
  2.    set -v
  3. else
  4.    set v
  5. fi
    凡是形如“[ 判断式 ] && 指令1 || 指令2”的形式,都可以视为一种隐形的if-then-else语法。


小结:
    
     在上述的条件测试方法中,[[]]和test、[]的意思和用法是相近的。区别是[[]]比test和[]更自由一点,因为[[]]不必担心一些转义字符的影响,比如[[ str < xyz ]]是正确的语法,但是在[]中,确要写成[ "str" \< "xyz" ]。在[[]]中<、>、&&、||等都可以自由使用,不必使用转义字符。此外,(( ))也不必理会上述所提到的转义字符的影响。

     在[[ 判断式 ]]中,如果使用 == 或 !=,且在这两个运算符右方的字符串没有加上单引号或双引号,则== 和 !=会视为想要对比该字符串所形成的“样式”,如果相等,则传回真值0,否则传回1.


  1. #!/bin/bash
  2. a="str"
  3. if [[ $a == ??? ]]; then        #用$a的值,对比样式???(3个字符的字符串)
  4.    echo "match"
  5. fi
  6. if [[ $a == "???" ]]; then        #判断$a与字符串???是否相等
  7.    echo "match"
  8. fi
    其他用法诸如:


  1. [[ "$str" == *. ]]          #*.这个样式是说,任意长度字符串,且最后一个是.
  2. [[ "$str" == *[.?\!] ]]     # *[.?\!] 这个样式是说,任意长度字符串,以.、?、!之一作为终止符


3、条件判断的真假值
   
   (1)关于文件属性的判断式

  1. 部分参数含义:

  2. -d file      #如果文件存在,且该文件是目录文件
  3. -e file      #如果文件存在        
  4. -f file      #如果文件存在,且该文件是一般文件
  5. -w file      #如果文件存在,且该文件具有可读属性
  6. -x file      #如果文件存在,且该文件具有可执行属性
  7. ...
     例如:

  1. #!/bin/bash
  2. [ -e "/etc/hosts" ] || (echo '/etc/hosts not exist'; exit 1)
  3. if [ "$?" -eq 1]; then
  4.    exit
  5. fi
  6. echo '/etc/hosts exist...'
    其中,行3用-e判断/etc/hosts是否存在,如果不存在,则( )开启一个子shell显示文件不存在的信息,然后传回离去状态值1. 行4,如果离去状态为1,就接触该Script。

   (2)关于字符串的条件判断式


  1. #部分参数含义

  2. -z 字符串                  #如果字符串长度为0(空串),真值
  3. -n 字符串                  #如果字符串长度不为0(非空串),真值
  4. 字符串1 = 字符串2           #如果两个字符串相同,真值
  5. 字符串1 == 字符串2          #如果两个字符串相同,真值
  6. 字符串1 != 字符串2          #如果两个字符串不相同,真值
  7. 字符串1 < 字符串2
  8. 字符串1 > 字符串 
  9. ...

     例如:

  1. #!/bin/bash
  2. if [ "$LOGNAME" != "root" ]; then
  3.   echo 'you must be root that you can do next'
  4.   exit 1
  5. fi
  6. echo 'you are the root ...'

   (3)关于算式的条件判断
     所谓算式,在此指其值或运算结果是数值(如整数、非字符串)。

  1. #部分参数含义:

  2. -eq      #参数1和参数2值相等
  3. -ne      #不相等
  4. -lt      #小于(<)
  5. -le      #小于等于
  6. -gt      #大于(>)
  7. -ge      #大于等于


   (4)关于Bash选项的条件判断

  1. -o set 的选项名称    # 如果该选项是开启状态,真值
    例如,

  1. #!/bin/bash
  2. set -o                                #选出目前shell中的选项
  3. if [ -o history ]; then
  4.    echo 'Bash history fuction is on'
  5. else
  6.    echo 'Bash history fuction is off'



4、case语法

   (1)case的语法结构如下:

  1. case 待测项 in
  2.     样式串行1) 命令区域1;;          #样式串行也可以用完整的扩号,如(样式串行1)
  3.     样式串行2) 命令区域2;;
  4.     样式串行3) 命令区域3;;
  5.       ...
  6.     *) 命令区域;;
  7. esac
     样式串行可以用字符串和通配符组成,默认是大小写敏感的,会区分大小写。如果样式串行有好几个字符串需要比对,要使用 | 隔开。字符 | 有“或”的意思。例如


  1. #!/bin/bash

  2. #shopt -s nocasematch            #样式匹配时,忽略大小写

  3. read yname
  4. case $yname in
  5.    Jack | John | Joe)
  6.        echo "well.."
  7.        echo "Long time no see."
  8.        ;;
  9.    Marry | May) 
  10.        echo 'Nice to meet you'
  11.        ;;
  12.    C*)                             #凡是以大写字母C开头的字符串,均符合对比
  13.        echo "oh? It is right?"
  14.        ;;
  15.    *) echo "hi";;
  16. esac
   
    (2)高级样式
     Bash的样式,可以由以下组件组成,称为样式串行:

  1. 字符串:如Jack
  2. 通配符:比如*表示任意长度字符串,???表示3个字符的字符串
  3. 字符集合:如[p-r]im表示pim、qim、rim
  4. 项目分隔符:|
  5.      
  6.     #如果Bash的选项extglob有打开: shopt -s extglob ,Bash还支持几个高级样式
  7. ?(样式串行): 如果符合0个或1个括号里的样式串行,就算比对符合
  8. *(样式串行): 如果符合0个以上的括号里的样式串行,就算比对符合
  9. (样式串行): 如果符合1个以上的括号里的样式串行,就算比对符合
  10. @(样式串行): 如果符合括号里样式串行的其中一个,就算比对符合
  11. !(样式串行): 只要不出现在括号里面的样式串行,就算比对成功
    
     例如:

  1. #!/bin/bash
  2. shopt -s extglob
  3. read yname
  4. case $yname in
  5.     j@(ac|xy|pq)k | john | joe)
  6.          echo "Long time no see"
  7.          ;;
  8.     *) 
  9.          echo "Hi~"
  10.          ;;
  11. esac
       其中,行6只要变量$yname是jack、jxyk、jpqk及john、joe之一,就对比成功。 对于高级样式,除了可以在case语法中使用之外,也可以在[[]]条件判断中使用,如下例:

  1. #!/bin/bash
  2. shopt -s extglob
  3. read cmd
  4. if [[ $cmd == @(declare|typeset) ]]; then   #只要是 declare和typeset中的一个就算匹配成功
  5.     echo 'match'
  6. fi


5、for循环

   for循环的运作方式,是将串行的元素一一取出,依次放入指定的变量中,然后重复执行含括的命令区域(在do和done之间),直到所有的元素取尽为止。其中,串行是一些字符串的组合,彼此用 $IFS 所定义的分隔符(如空格)隔开,这些字符串称为字段。
   for的语法结构如下:

  1. for 变量 in 串行
  2. do
  3.    命令区域
  4. done
    
    例如,for循环经常用在分隔字符串行,取出字段元素值。
  1. IFS=':'
  2. PL="root:x:0:0:root:/root:/bin/bash"
  3. for f in $PL
  4. do
  5.    echo $f
  6. done
     比较经典的做法是取出CSV文件的字段。CSV文件是一种用,(逗号)分隔数据字段的纯文本文件,适合担任数据库之间汇入、到处数据的中介。取出CVS文件各行字段的做法如下:

  1. #!/bin/bash
  2. declare -i i=0
  3. for line in $(cat cvsfile.txt)         #取出每行
  4. do
  5.    i=i+1
  6.    echo -n "第 $i 行的字段有: "
  7.    save_ifs=$IFS                       #保存默认IFS
  8.    IFS=','                             #重新定义IFS为,
  9.    for f in $line                      #依据IFS,取出每行的每个字段
  10.    do
  11.       echo -n $f ' '
  12.     done
  13.    IFS=$save_ifs                       #恢复IFS为默认值
  14.    echo
  15. done
    在例如用for程序来列出/var目录下各个子目录占磁盘空间的大小,如下:

  1. #!/bin/bash
  2. DIR="/var"
  3. cd $DIR
  4. for f in $(ls $DIR)                #对/var目录下的每一个文件,进行for处理
  5. do
  6.    [ -d $f ] && du -s $f           #[ -d $f ]如果该文件是目录, du -s 计算占用磁盘大小
  7. done


6、while 循环
    
    while循环的语法: 
  1. while 条件测试
  2. do
  3.    命令区域
  4. done
    例如:

  1. #!/bin/bash
  2. declare -i i=1
  3. declare -i sum=0
  4. while ((i<=10))
  5. do
  6.    let sum+=1
  7.    let ++i
  8. done
     while循环的经典用法是搭配转向输入,读取文件是内容,做法如下:

  1. #!/bin/bash
  2. while read line    #用read由标准输入读取数据,放入变量line中,如果读到的数据非空,就进入循环
  3. do
  4.    echo $line
  5. done < cvsfile     #将cvsfile的内容转向输入,交给read处理
     再比如,

  1. #!/bin/bash
  2. IFS=':'
  3. cat /etc/passwd | {       #吧/etc/passwd的内容通过管道丢给{ }指令组,传给行6的read读取

  4. while read f1 f2 f3 f4 f5 f6 f7          #读取各行账号数据,并将个字段放入变量f1—f7中
  5. do
  6.     echo "账号: $f1,login shell 是: $f7"
  7. done
  8. }

7、until 循环 

   until 循环的语法:
   与while条件测试不同的是,while测真值,until测假值
  1. until 条件测试
  2. do
  3.     命令区域
  4. done

8、break 和 continue

    想要提早结束循环,可以在循环中使用break命令。执行break时,会跳出一层的循环,如果想要跳出多层循环,可以在break命令之后加上层数n(n一定要大于或等于1).与break不同的是,continue会跳过本次循环,重新由下一个循环开始执行。

  1. #!/bin/bash
  2. for ((i=1;i<=10;i++))           #这是for语法的另外一种写法,类C式
  3. do
  4.    if [ $i -eq 6 ]; then
  5.       break                     #跳出循环体,直接执行行9
  6.       #continue                 #跳出此次循环,继续有下一个循环开始执行
  7.    fi
  8.    echo $i
  9. done

阅读(810) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Bash Shell学习笔记--高级变量

给主人留下些什么吧!~~