shell 流程控制

 shell的流程控制

在Bash Shell中,流程控制有两大类:“选择”和“循环”。属于“选择”的有:if、case;属于“循环”的有:for、while、until;命令select即属于“选择”,也属于“循环”。不管是哪一种,均需进行条件测试,在根据测试结果,决定程序流程进行的方向。

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

1:if条件判断

简易的if语法:if-then-else

(1)if-then

if 条件测试;then

命令区域

fi

(2)if-then-else

if 条件测试1;then

    命令区域1

elif条件测试2;then

    命令区域2

else

    命令区域3

fi

2:条件测试的写法

(1)执行某一个命令的结果

包括管道命令: 命令1 | 命令2 | 命令3 ,称为pipeline,其结束状态为最后一个命令执行的结果。

范例:

  
  
  
  
  1. #!/bin/bash 
  2. #grep -q "rm" fn.sh是寻找fn.sh文件里是否包含关键词rm。选项-q表示不显示,仅借助$?来传回执行结果。
  3. if grep -q "rm" fn.sh; then 
  4.    echo "find rm command ." 
  5. else 
  6.    echo "not find." 
  7. fi 

(2)传回某一命令执行结果的相反值

其形式为:!命令

注意:!和命令之间要有空格符隔开。

如果命令传回值为0,则加上!之后传回值为1;反之,如果命令传回值为非0,则加上!之后,传回值为0.

  
  
  
  
  1. #!/bin/bash  
  2. if ! grep -q "rm" fn.sh; then  
  3.    echo "find rm command ."  
  4. else  
  5.    echo "not find."  
  6. fi  

(3)使用复合命令:((算式))

如果算式的运算结果不为0,则传回真值(0),否则如果运算结果为0,则传回假值(1)。

 (4)使用Bash关键词‘[[’、‘]]’组成的式子:[[判断式]]

判断式会传回真假值,传回0为真,非0为假。注意,[[的后面、]]的前面,都至少要有一个(含)以上的空格符才行。

(5)使用内置命令:test判断式

test是Bash的内置命令,可传回“判断式”的结果,真值传回 0,假值传回1.

(6)使用内置命令:[]

其形式为:[判断式]

[]和test的用法是相同的,两者可更改互换。

(7)使用-a,-o进行逻辑组合:

例如:

[ -r filename1 -a -x filename ]

如果filename1可读且可执行,则为真。-a即“且”之意。

[ -r filename1 -o -x filename ]

如果filename1可读或可执行,则为真。-o即“或”之意。

(8)命令1 && 命令2

&&为为逻辑的AND,其运作方式是:如果“命令1”执行结果为真,才会执行“命令2”;如果两个皆为真,则传回真值0,否则传回假值1 。

凡是“[判断式] && 指令”的形式,就视为一种隐形的if-then语法。

例如:

  
  
  
  
  1. # 如果$ps1的变量值不为空,就执行return指令。
  2. [ -z "$PS1" ] && return 
  3. #如果/proc/net/if_inet6存在,就显示主机的核心支持IPv6协议。
  4. [ -f /proc/net/if_inet6 ] && echo 'The macshine is support IPv6.'

(9)命令1 || 命令2

||称为逻辑的OR,其运作方式是:如果“命令1”执行结果为假,才会执行“命令2”;如果两个之中有一个为真,则传回真值0,否则传回假值1 。

||的特性也可以当作一种隐形的if语法:例如

  
  
  
  
  1. prefix="/home"
  2. defpath="/usr/local/bin"
  3. #因为$prefix非空,所以,${prefix:-}变量扩展的传回值为prefix的变量值(非空),[ -z ${prefix:-}]
  4. #对空值条件测试失败,其结果为假,根据||的特性,会接着执行prefix=${defpath%/*},它会由$defpath后方
  5. #删去符合样式/*的最短字符串,即删除/bin,因此$prefix的值为/usr/local。
  6. [ -z ${prefix:-} ] || prefix=${defpath%/*}

 (10)&&和||合用

&&和||合用,也可以有if-then-else的效果,例如:

[ -n ${DEBUG:-} ] && set -v || set +v

这行代码使用-n测试变量DEBUG是否有设非空值,如果有,表示要进行排错,接着执行逻辑AND的下一个指令:set -v;如果无,则不进行排错,而改执行逻辑OR的下一个指令:set +v,它会把显示程序代码的功能关闭。

  
  
  
  
  1. if [ -n "$DEBUG" ];then 
  2.       set -v 
  3. else 
  4.       set +v 
  5. fi 

 注意:在条件测试的方法中,[[]]和test、[]的意思和用法是相近的,但[[]]比test和[]更自由一点,因为[[]]不必担心某些Bash特殊字符对运算符的影响,不必写一堆转义字符。

3:case条件判断

case的语法

  
  
  
  
  1. case 待测项 in
  2. 样式串行1) 命令区域1;
  3. 样式串行1) 命令区域2;
  4. 样式串行1) 命令区域3;
  5. ......
  6. *) 命令区域;;
  7. esac

 说明:

如果“待测项”和某一样式串行对比符合的话,case会选择性的执行该样式后面的命令区域。

命令区域,可以使单一指令或多行指令,但最后一个指令要以;;结束。

样式串行可用字符串和通配符组成,默认会区别大小写,换言之,Jack和jack是不同的样式。

如果样式串行中有好几个字符串要对比,要用|隔开。字符|有“或”的意思,意即:只要符合其之一,就算对比成功。

样式串行可写成'(样式串行)',或者省略左边的括号,可写成‘样式串行)’。一般,以后面这个写法,较受欢迎。

样式*)通常放在case最后一个区域,用来捕捉不符合样式的其他所有情况。

最后esac结束case语法。esac是case的反写。

nocasematch,可以让Base在对比样式时忽略大小写。

例如:shopt -s nocasematch 

 (1)高级样式

 Base的样式,可又一下组件组成,成为样式串行:

  • 字符串:如Jack。
  • 通配符:比如*表示任意长度的字符串,也包括空字符串;C*表示以C开头的字符串;????表示4个字符的字符串。
  • 字符集合:如[p-r]im,表示pim、qim、rim。
  • 项目分隔符 |。

如果样式有好几项组件,彼此之间用|隔开,例如 ps | top | w 。对比时,只要符合其中一项,就算对比成功。

另外,如果Bash的选项extglob有打开,例如

shopt -s extglob

那么,Bash还支持几种高级样式:

  • ?(样式串行):如果符合0个或1个括号里的样式串行,就算对比符合。
  • *(样式串行):如果符合0个以上括号里的样式串行,就算对比符合。
  • +(样式串行):如果符合括号里1个以上样式串行,就算对比符合。
  • @(样式串行):如果符合括号里样式串行的其中一个,计算对比符合。
  • !(样式串行):只要不是出现在括号里的样式串行,就算对比符合。

4:for循环

for循环的运作方式,是将串行的元素一一取出,依序放入制定的变量中,然后重复执行含括的的命令区域(在do和done之间),直到所有元素取尽为止。

其中,串行是一些字符串的组合,彼此用$IFS所定义的分隔符(如空格符)隔开,这些字符串被称为字段。

for的语法结构为:

 

      
      
      
      
  1. for 变量 in 串行
  2. do
  3. 命令区域
  4. done

说明:行1,将串行的字段迭代放入变量中。

行2~4,接着重复执行do和done之间的命令区域,直到串行中每一个字段均处理过为止。

例如:查看/var目录下各子目录占用磁盘的情况。

  
  
  
  
  1. #!/bin/bash 
  2.  
  3. DIR="/var" 
  4. cd $DIR 
  5. for f in $(ls $DIR) 
  6. do 
  7.   [ -d $f ] && du -s $f 
  8. done 

另外一种for的用法:

  
  
  
  
  1. for ((初始条件;终止条件;异动项)) 
  2. do 
  3.    命令区域 
  4. done 

for无穷循环

  
  
  
  
  1. for ((;1;1)) 
  2. do 
  3.    命令区域 
  4. done 

 5:while循环

while的语法:

  
  
  
  
  1. while 条件测试 
  2.  
  3. do 
  4.      命令测试 
  5. done 

 说明:

  • 行1,首先进行条件测试,如果传回值为0(条件测试为真),则进入循环,执行命令区域,否则不进入循环,结束while命令。
  • 行3,执行命令区域,这些命令中,应该要有改变条件测试的命令,这样,才有机会在有限步骤后结束执行while(除非想要执行无穷循环)。
  • 行4,回到行1,执行while命令。

例如:

  
  
  
  
  1. #!/bin/bash 
  2. declare -i i=1 
  3. declare -i sum=0 
  4.  
  5. while ((i<=10)) 
  6. do 
  7.      let sum+=i 
  8.      let ++i 
  9. done 
  10.  
  11. echo $sum 

使用while循环,读取文件内容

while循环,经典的用法就是搭配转向输入,读取文件的内容。

例如:

  
  
  
  
  1. #!/bin/bash 
  2. #filename:readfile.sh
  3.  
  4. while read line 
  5. do 
  6.    echo $line 
  7. done < cvsfile 

 

  
  
  
  
  1. #!/bin/bash 
  2. #filename:readfile2.sh 
  3.  
  4. IFS=':' 
  5. while read f1 f2 f3 f4 f5 f6 f7 
  6. do 
  7.    echo "账号:$f1,login Shell是:$f7" 
  8. done < "/etc/passwd" 

 

  
  
  
  
  1. #!/bin/bash
  2. #filename:readfile3.sh
  3.  
  4. IFS=':'
  5. cat /etc/passwd | {
  6. while read r1 r2 r3 r4 r5 r6 r7
  7. do
  8. echo "账号:$f1,login shell是:$f7"
  9. done
  10.  
  11. }

 while无穷循环

  
  
  
  
  1. while ((1)) 
  2. do 
  3.    echo "夜不眠" 
  4. done 

 把((1))改成[1]也可以。

或者

  
  
  
  
  1. while true 
  2. do 
  3.    echo '夜不眠' 
  4. done 

 或者

  
  
  
  
  1. while : 
  2. do 
  3.     echo '夜不眠' 
  4. done 

按下Ctrl+C,可以终止循环。

6.until循环

while循环的测试条件是真值,until循环的测试值是假值。

until的语法:

  
  
  
  
  1. until 条件测试 
  2. do 
  3.      命令区域 
  4. done 

说明:

行1,如果条件测试结果为假(传回值不为0),就进入循环。

行3,执行命令区域。这些命令中,应该有改变条件测试的命令,这样,才有机会在有限步骤结束执行until的循环(除非你想要执行无穷循环)。

行4,回到行1,执行until命令。

until无穷循环

until无穷循换的写法如下:

  
  
  
  
  1. until ((0)) 
  2. do 
  3.     echo 'Bash forever.' 
  4. done 

或者:

  
  
  
  
  1. until false 
  2. do 
  3.     echo 'Bash forever.' 
  4. done 

按下ctrl+c,可以终止循环。

7.select命令

 select命令可以建立简易的列表,其语法结构和for一样。

select的语法如下:

  
  
  
  
  1. select 选项变量 in 串行 
  2. do  
  3.       命令区域 
  4. done 

 说明:

  • 行1,select命令建立一个列表。列表的选项,即串行中的各个字段。列表的提示符号由Bash的内置变量PS3来定义,默认值是#?。只要改变PS3的值,用户可以自定义提示符号。select会给各个选项一个编号,编号由1开始递增。当使用者键入编号,选择其中某一选项是时,该选项的内容就设值给选项变量,而键入的编号值则放入RERLY变量中。
  • 行3,使用者每键入一次编号,就执行一次命令区域。
  • 行4,回到行1执行select命令,再一次显示列表。由此可见:select具有循环的功能。
  • 想要结束select列表,可在命令区域输入break命令,或按Ctrl+D结束输入。
  
  
  
  
  1. #!/bin/bash 
  2.  
  3. PS3='请选择:' 
  4. select f in * 
  5. do 
  6.    echo "你键入的编号是$REPLY,选择的文件是:$f" 
  7. done 

说明:

  • 行3,修改PS3的内容,自定义提示符号。
  • 行4,由目前的工作目录,读取所有文件(即通配符*的用意),以各个文件名选项,,建立列表。
  • 行6,显示用户选择的结果。

 8:break和continue

break命令

对于前面提到的4种循环for、while、until、select而言,如果想要提早结束循环,可在循环中使用break命令。执行break时,会跳出一层的循环,如果想要跳出多层循环,可在break命令之后加上层数n(n一定要大于或等于1)。

  
  
  
  
  1. #!/bin/bash 
  2.  
  3. for ((i=1;i<=10;i++)) 
  4. do 
  5.      for ((j=1;j<=10;j++)) 
  6.          do 
  7.             r=$((i+j)) 
  8.             if [ $r -eq 19 ];then 
  9.             break 2 
  10.             fi 
  11.            echo $r 
  12.       done 
  13. done 

 

 continue名利

continue一样可以运用在for、while、until、select这4种循环语法中。和break不同的是continue会跳过本次循环,重新由下一个循环开始执行。 

  
  
  
  
  1. #!/bin/bash 
  2.  
  3. for ((i=1;i<=10;i++)) 
  4. do 
  5.        if [ $i -eq 6 ];then 
  6.          continue 
  7.        fi 
  8.     echo $i 
  9. done 
  10.                 

 如果有多层循环,可以在continue后面指定由哪一层的循环重新开始执行。例如:continue 2,表示从里面往外跳出2层循环,然后由哪一层的循环开始。

 

 

 

 

你可能感兴趣的:(shell,流程控制,while,continue,for,if,until)