9. Shell 流程控制

和Java、PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法):

  1. <?php
  2. if (isset($_GET["q"])) {
  3. search(q);
  4. }
  5. else {
  6. // 不做任何事情
  7. }

在sh/bash里可不能这么写,如果else分支没有语句执行,就不要写这个else。


if else

if

if 语句语法格式:

  1. if condition
  2. then
  3. command1
  4. command2
  5. ...
  6. commandN
  7. fi

写成一行(适用于终端命令提示符):

  1. if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi

末尾的fi就是if倒过来拼写,后面还会遇到类似的。

if else

if else 语法格式:

  1. if condition
  2. then
  3. command1
  4. command2
  5. ...
  6. commandN
  7. else
  8. command
  9. fi

if else-if else

if else-if else 语法格式:

  1. if condition1
  2. then
  3. command1
  4. elif condition2
  5. then
  6. command2
  7. else
  8. commandN
  9. fi

示例:

  1. a=10
  2. b=20
  3. if [ $a == $b ]
  4. then
  5. echo "a 等于 b"
  6. elif [ $a -gt $b ]
  7. then
  8. echo "a 大于 b"
  9. elif [ $a -lt $b ]
  10. then
  11. echo "a 小于 b"
  12. else
  13. echo "没有符合的条件"
  14. fi

输出结果:

  1. a 小于 b

if else语句经常与test命令结合使用,如下所示:

  1. num1=$[2*3]
  2. num2=$[1+5]
  3. if test $[num1] -eq $[num2]
  4. then
  5. echo '两个数字相等!'
  6. else
  7. echo '两个数字不相等!'
  8. fi

输出:

  1. 两个数字相等!

for 循环

一般格式:

  1. for var in item1 item2 ... itemN
  2. do
  3. command1
  4. command2
  5. ...
  6. commandN
  7. done

写成一行:

  1. for var in item1 item2 ... itemN; do command1; command2 done;

  当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。
  in列表是可选的,如果不用它,for循环使用命令行的位置参数。
例如,顺序输出当前列表中的数字:

  1. for loop in 1 2 3 4 5
  2. do
  3. echo "The value is: $loop"
  4. done

输出:

  1. The value is: 1
  2. The value is: 2
  3. The value is: 3
  4. The value is: 4
  5. The value is: 5

顺序输出字符串中的字符:

  1. for str in 'This is a string'
  2. do
  3. echo $str
  4. done

输出结果:

  1. This is a string

while语句

while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为:

  1. while condition
  2. do
  3. command
  4. done

以下是一个基本的while循环,测试条件是:如果int小于等于5,那么条件返回真。int从0开始,每次循环处理时,int加1。运行上述脚本,返回数字1到5,然后终止。

  1. #!/bin/sh
  2. int=1
  3. while(( $int<=5 ))
  4. do
  5. echo $int
  6. let "int++"
  7. done

输出:

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5

使用中使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量,具体可查阅:Bash let 命令
。while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量FILM,按结束循环。

  1. echo '按下 <CTRL-D> 退出'
  2. echo -n '输入你最喜欢的电影名: '
  3. while read FILM
  4. do
  5. echo "是的!$FILM 是一部好电影"
  6. done

输出:

  1. 按下 <CTRL-D> 退出
  2. 输入你最喜欢的电影名: w3cschool菜鸟教程
  3. 是的!w3cschool菜鸟教程 是一部好电影

无限循环

无限循环语法格式:

  1. while :
  2. do
  3. command
  4. done

或者

  1. while true
  2. do
  3. command
  4. done

或者

  1. for (( ; ; ))

until 循环

until循环执行一系列命令直至条件为真时停止。
until循环与while循环在处理方式上刚好相反。
一般while循环优于until循环,但在某些时候—也只是极少数情况下,until循环更加有用。
until 语法格式:

  1. until condition
  2. do
  3. command
  4. done

条件可为任意测试条件,测试发生在循环末尾,因此循环至少执行一次—请注意这一点。


case

Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case语句格式如下:

  1. case in
  2. 模式1)
  3. command1
  4. command2
  5. ...
  6. commandN
  7. ;;
  8. 模式2
  9. command1
  10. command2
  11. ...
  12. commandN
  13. ;;
  14. esac

case工作方式如上所示。取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
下面的脚本提示输入1到4,与每一种模式进行匹配:

  1. echo '输入 1 到 4 之间的数字:'
  2. echo '你输入的数字为:'
  3. read aNum
  4. case $aNum in
  5. 1) echo '你选择了 1'
  6. ;;
  7. 2) echo '你选择了 2'
  8. ;;
  9. 3) echo '你选择了 3'
  10. ;;
  11. 4) echo '你选择了 4'
  12. ;;
  13. *) echo '你没有输入 1 到 4 之间的数字'
  14. ;;
  15. esac

输入不同的内容,会有不同的结果,例如:

  1. 输入 1 4 之间的数字:
  2. 你输入的数字为:
  3. 3
  4. 你选择了 3

跳出循环

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue。

break 命令

break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。

  1. #!/bin/bash
  2. while :
  3. do
  4. echo -n "输入 1 到 5 之间的数字:"
  5. read aNum
  6. case $aNum in
  7. 1|2|3|4|5) echo "你输入的数字为 $aNum!"
  8. ;;
  9. *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
  10. break
  11. ;;
  12. esac
  13. done

执行以上代码,输出结果为:

  1. 输入 1 5 之间的数字:3
  2. 你输入的数字为 3!
  3. 输入 1 5 之间的数字:7
  4. 你输入的数字不是 1 5 之间的! 游戏结束

continue

  continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
对上面的例子进行修改:

  1. #!/bin/bash
  2. while :
  3. do
  4. echo -n "输入 1 到 5 之间的数字: "
  5. read aNum
  6. case $aNum in
  7. 1|2|3|4|5) echo "你输入的数字为 $aNum!"
  8. ;;
  9. *) echo "你输入的数字不是 1 到 5 之间的!"
  10. continue
  11. echo "游戏结束"
  12. ;;
  13. esac
  14. done

运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo “Game is over!” 永远不会被执行。


esac

case的语法和C family语言差别很大,它需要一个esac(就是case反过来)作为结束标记,每个case分支用右圆括号,用两个分号表示break。