bash 流程控制语句

bash 流程控制语句

若没有流程控制语句,bash脚本程序将只能顺序执行,那满足不了我们的需求

程序的结构有如下三种

  • 顺序结构
  • 选择结构
  • 循环结构

在bash脚本中选择结构使用if语句,循环结构有forwhileuntil三种语句。

if 语句

语法:
if CONDITION;then
COMMANDS
elif CONDITION;then
COMMANDS
...
else
COMMANDS
fi

# CONDITION 为选择条件,使用测试表达式
# COMMANDS 为选择执行的命令集合

实例 1:编写脚本/root/bin/createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息

[root@localhost 17]# cat 17-1.sh 
#!/bin/bash

#---------------------------------------
# Author: zhuenbiao
# File Name: 17-1.sh
# Create Time: 2017-08-24 18:35:19
# Modified Time: 2017-08-24 18:35:19
# Version: 0.1
# Description:
#---------------------------------------

# Check Whether user inputed a arugments, if inputhed ,assigned it to varialbe
if [ "$#" -eq 1 ]; then
user="$1"
else
i=1
while [ -z "$user" ]; do
read -p "Please input a user name: " user
if [ "$i" -ge 3 ];then
exit 10
fi
((i++))
done
fi

# Check whether a user exists
# method 1
#id -u "$user" &> /dev/null

# method 2
#getent passwd "$user" &> /dev/null

# method 3
grep "^${user}\>" /etc/passwd &> /dev/null

if [ "$?" -eq 0 ]; then
echo "$user is exists"
exit 11
else
useradd "$user" &> /dev/null
if [ "$?" -eq 0 ]; then
uuidgen | tr -d "-" | echo "$user: `head -c 10`" | tee -a passwd.log | passwd "$user" --stdin &> /dev/null
passwd -e "$user" &> /dev/null
echo "$user added successfully"
else
echo "$user added failed"
fi
fi

case 语句

语法:
case $var init
PAT1)
COMMANDS
;;
PAT2)
COMMANDS
;;
...
*)
COMMAND
;;
esac

# PAT支持glob通配符和逻辑或功能
* :任意个数,任意字符
? :任意单个字符
[...] :匹配单个字符
a|b :a或b

实例: 制作一个简单的菜单

#!/bin/bash

#---------------------------------------
# Author: zhuenbiao
# File Name: case_select.sh
# Create Time: 2017-08-27 05:46:25
# Modified Time: 2017-08-27 05:46:25
# Version: 0.1
# Description:
#---------------------------------------

# Define prompt of select
PS3="Choosing your menu: "

sum=0
# select struct
select menu in IrishCoffee Espresson IceTea HouserWine OrangeJuice TomatoJuice QUIT;do
case $REPLY in
1)
price=10
sum=$((sum+price))
echo -e "$menu: $price yuan\t Total: $sum yuan"
;;
2)
price=20
sum=$((sum+price))
echo -e "$menu: $price yuan\t Total: $sum yuan"
;;
3)
price=15
sum=$((sum+price))
echo -e "$menu: $price yuan\t Total: $sum yuan"
;;
4)
price=13
sum=$((sum+price))
echo -e "$menu: $price yuan\t Total: $sum yuan"
;;
5)
price=16
sum=$((sum+price))
echo -e "$menu: $price yuan\t Total: $sum yuan"
;;
6)
price=19
sum=$((sum+price))
echo -e "$menu: $price yuan\t Total: $sum yuan"
;;
7)
break
;;
*)
echo "Sorry, Please chose others"
;;
esac
done

cat << EOF

====================================
# Thank you, please pay $sum yuan
====================================

EOF

执行结果如下所示

[root@localhost jobs]# bash case_select.sh 
1) IrishCoffee 3) IceTea 5) OrangeJuice 7) QUIT
2) Espresson 4) HouserWine 6) TomatoJuice
Choosing your menu: 3
IceTea: 15 yuan Total: 15 yuan
Choosing your menu: 2
Espresson: 20 yuan Total: 35 yuan
Choosing your menu: 6
TomatoJuice: 19 yuan Total: 54 yuan
Choosing your menu: 7

====================================
# Thank you, please pay 54 yuan
====================================

for 语句
for语句有两种语法

  • 语法一
for var in LIST_TABLE
do
COMMNDS
done
-------------------------------------
LIST_TABLE 为列表,有以下几种情况
1. 空格隔开的字符串:
e.g
1 2 3
nice good ok

2. 使用{}生成的整数
{start..end..setp}
e.g
{1..100}
{1..20..2}
{40..20..2}

3. 通过命令生成的列表
只有能生成各字符串直接带一个空格的命令均可以
$(COMMAND)
`COMMAND`
e.g
`ls`
$(tail -1 /etc/passwd | xargs -d ":")

4. 使用glob通配的
* 当前目录下的文件
/etc/*.sh /etc/目录一下以.sh结尾的文件

5. 变量引用
$@
$*

  • 语法二
for((EXP11,EXP12...; EXP2; EXP31,EXP32...));do
COMMAND
done

------------
解释:
(()) 里面的语句为C语言风格,变量不用加$符号
EXP11,EXP12.. : 初始化表达式,开始for循环执行一次
EXP2 : 判断语句,真 才执行循环
EXP31,EXP32... :执行完本次循环的最后一条语句才执行该表达式

实例: 打印九九乘法表

#!/bin/bash

#---------------------------------------
# Author: zhuenbiao
# File Name: for-7.sh
# Create Time: 2017-08-24 23:17:34
# Modified Time: 2017-08-24 23:17:34
# Version: 0.1
# Description:
#---------------------------------------

for i in {1..9};do
for j in `seq $i`;do
product=$(($i*$j))
if [ "${#product}" -eq 1 ];then
echo -e "$j*$i=$product \c"
else
echo -e "$j*$i=$product \c"
fi
done
echo
done

执行结果:

[root@localhost 17]# bash for-7.sh 
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81

while 语句

  • 语法
while CONDITION;do
COMMAND
done

-----------------
解释:
CONDITION为真则执行循环体 <=添加到条件测试
:
true
``
均为真,只要退出状态码为0均为真

-----------------
判断条件也可以上使用(())的C语言风格
while ((CONDITION));do
COMMAND
done
(()) 里面的语句为C语言风格,变量不用加$符号

-----------------
配合read一起使用
while read var;do
COMMAND
done<FILE_NAME

stdout | while read var;do
COMMAND
done

解释:
read 每次读取一行的内容,通过while循环读取多行内容,当读到最后一行的时候,read执行错误,退出while循环
read 是可以接收标准输入的,所以任何使用标准输入的方式均可以用在此处

实例:打印国际象棋棋盘

#!/bin/bash

#---------------------------------------
# Author: zhuenbiao
# File Name: chess.sh
# Create Time: 2017-08-26 22:58:28
# Modified Time: 2017-08-26 22:58:28
# Version: 0.1
# Description:
#---------------------------------------

# Define the color of chess
color1="\033[47m \033[0m"
color2="\033[45m \033[0m"

# while struct
i=1
while ((i<=64));do
echo -ne "$color1"
echo -ne "$color2"

# newline
if [ $[i%4] -eq 0 ];then
echo
fi

# change color
if ((i%8 == 0));then
temp_color="$color1"
color1="$color2"
color2="$temp_color"
fi

let i++
done

执行结果:

Alt text

until
until 与 while 功能一样,差别在于while 条件为真执行,而until条件为假执行。

  • 语法
until CONDITION;do
COMMAND
done
-------------------

CONDITION为假则执行循环体

select
select 主要用来打印菜单选项

  • 语法
select VAR in LIST_TABLE; do
COMMAND
done

---------------------
解释:
作用: 当执行Select语句时,列表里的元素将每个元素一行的方式输出到屏幕上,并提示用户输入列表编号(输入数字),提示符是由PS3所定义的,用户输入编号后,列表将编号所对应的值赋值给变量VAR,编号赋值给REPLY。然后执行循环体内的命令。可以在循环体内引用变量VAR和REPLY。命令中若没有退出命令(如:如break,exit),则将死循环。不过我们可以发送信号SIGINT(ctrl+C) 或 按Ctrl+D退出。

PS3 :设定提示符
e.g PS3="select your menu: "
REPLY : 所选择编号

循环控制语句
执行循环的过程中,我们可以根据条件提前终止循环的执行,或跳过某次循环不执行。通过使用命令breakcontinue来实现

continue [n]
Resume for, while, or until loops.
跳过本次[n]层循环,即当前循环continue后面的代码将不执行。

break[n]
Exit for, while, or until loops.
退出[n]层循环,即当遇到break后就退出循环代码。

shift[n]
将位置参数左移位[n]个, 即遇到shift[n]命令就删除前[n]个位置参数。