shell编程-09-case条件语句的应用实践
case条件语句相当于多分支的if/elif/else条件语句,但是它比这些条件语句看起来更规范更工整,常被应用于实现系统服务启动脚本等企业应用场景中。
在case语句中,程序会将case获取的变量的值与表达式部分的值1、值2、值3等逐个进行比较,如果获取的变量值和某个值(例如值1)相匹配,就会执行值(例如值1)后面对应的指令(例如指令1,其可能是一组指令),直到执行到双分号(; ; )才停止,然后再跳出case语句主体,执行case语句(即esac字符)后面的其他命令。
如果没有找到匹配变量的任何值,则执行“*)”后面的指令(通常是给使用者的使用提示),直到遇到双分号(;; )(此处的双分号可以省略)或esac结束,这部分相当于if多分支语句中最后的else语句部分。另外,case语句中表达式对应值的部分,还可以使用管道等更多功能来匹配。
9.1 case 条件语句的语法
说明:当变量的值等于值1时,执行指令1;等于值2时执行指令2,以此类推;如果都不符合,则执行“*)”后面的指令,即指令3。此外,注意不同行内容的缩进距离。
case条件语句的语法格式为:
case 变量 in
值1)
指令
;;
值2)
指令
;;
*)
指令
esac
case条件语句的执行流程逻辑图如图
9.2 case条件语句实践
9.2.1 case实现输出菜单颜色显示
范例9-2:执行shell脚本,打印一个如下的水果菜单:
(1)apple
(2)pear
(3)banana
(4)cherry
当用户输入对应的数字选择水果的时候,告诉他选择的水果是什么,并给水果单词加上一种颜色(随意),要求用case语句来实现。
预备知识:
[root@zabbix 0508]# echo -e "\e[1;31m 红色字 \e[0m"
红色字
在上述命令中:
- echo -e可以识别转义字符,这里将识别特殊字符的含义,并输出。
- \E可以使用\033替代。
- “[1”数字1表示加粗显示(可以加不同的数字,以代表不同的意思,详细信息可用man console_codes获得)。
- 31m表示为红色字体,可以换成不同的数字,以代表不同的意思。
- “红色字oldboy”表示待设置的内容。
- “[0m”表示关闭所有属性,可以换成不同的数字,以代表不同的意思。
有关ANSI控制码的说明如下。
- \33[0m 表示关闭所有属性。
- \33[1m 表示设置高亮度。
- \33[4m 表示下划线。
- \33[5m 表示闪烁。
- \33[7m 表示反显。
- \33[8m 表示消隐。
- \33[30m -- \33[37m 表示设置前景色。
- \33[40m -- \33[47m 表示设置背景色。
console codes的更多知识可以参考man console_codes
case方式实现脚本:
[root@zabbix 0508]# cat menu.sh
#!/bin/bash
RED_COLOR='\E[1;31m'
GREEN_COLOR='\E[1;32m'
YELLOW_COLOR='\E[1;33m'
BLUE_COLOR='\E[1;34m'
PINK_COLOR='\E[1;35m'
RES='\E[0m'
function usage(){
echo "USAGE: $0 {1|2|3|4}"
exit 1
}
function menu(){
cat <<- zfd
1.apple
2.pear
3.banana
4.cherry
zfd
return 1
}
function choose(){
read -p "pls select a num:" num
case "$num" in
1)
echo -e "${RED_COLOR}apple${RES}"
;;
2)
echo -e "${GREEN_COLOR}pear${RES}"
;;
3)
echo -e "${YELLOW_COLOR}banana${RES}"
;;
4)
echo -e "${BLUE_COLOR}cherry${RES}"
;;
*)
usage
esac
return 2
}
function main(){
menu
choose
}
main
9.3 实践:给输出的字符串加颜色
在Linux脚本中,可以通过echo的-e参数,结合特殊的数字给不同的字符加上颜色并显示。
不同的数字对应不同的字体颜色,详情请参见系统帮助(来自使用man console_codes命令的结果)。
9.3.1 不同数字表示不同内容的颜色---字体颜色
内容的颜色可用数字表示,范围为30~37,每个数字代表一种颜色。代码如下:
echo -e "\e[1;30m 黑色字 \e[0m"
echo -e "\e[1;31m 红色字 \e[0m"
echo -e "\e[1;32m 绿色字 \e[0m"
echo -e "\e[1;33m 棕色字 \e[0m"
echo -e "\e[1;34m 蓝色字 \e[0m"
echo -e "\e[1;35m 洋红色字 \e[0m"
echo -e "\e[1;36m 蓝绿色字 \e[0m"
echo -e "\e[1;37m 白色字 \e[0m"
# 以上\e均可换为\033;echo -e "\033[1;30m 黑色字 \033[0m" ;
## 1表示加粗
不同的数字对应的字体颜色
9.3.2 case语句给输出的字符串加
范例9-5:请开发一个给指定内容加指定颜色的脚本。
要求:使用case语句及通过脚本传入指定内容和指定颜色,在脚本命令行传2个参数,给指定的内容(第一个参数)加指定的颜色(第二个参数)
[root@zabbix 0508]# cat case2.sh
#!/bin/bash
function usage(){
echo "Usage: $0 content {red|yellow|blue|green}"
exit 1
}
RET_VAL=0
function color(){
RED_COLOR="\e[1;31m"
GREEN_COLOR="\e[1;32m"
YELLOW_COLOR="\e[1;33m"
BLUE_COLOR="\e[1;34m"
RES="\e[0m"
case $2 in
red)
echo -e "${RED_COLOR} $1 $RES"
;;
yellow)
echo -e "${YELLOW_COLOR}${1}$RES"
;;
blue)
echo -e "${BLUE_COLOR}${1}$RES"
;;
green)
echo -e "${GREEN_COLOR}${1}$RES"
;;
*)
usage
esac
return $RET_VAL
}
function main(){
[ $# -eq 2 ] || usage
color $1 $2
RET_VAL=$?
return $RET_VAL
}
main $* ## $* 接收命令行的所有参数并传入main函数
9.3.3 给输出的字符串加---背景颜色
范例9-6:给输出的字符串加不同的背景颜色。
字的背景颜色对应的数字范围为40~47,代码如下。
echo -e "\e[40;37m 黑底白字 \e[0m"
echo -e "\e[41;37m 红底白字 \e[0m"
echo -e "\e[42;37m 绿底白字 \e[0m"
echo -e "\e[43;37m 棕底白字 \e[0m"
echo -e "\e[44;37m 蓝底白字 \e[0m"
echo -e "\e[45;37m 洋红底白字 \e[0m"
echo -e "\e[46;37m 蓝绿底白字 \e[0m"
echo -e "\e[47;30m 白底黑字 \e[0m"
# 以上\e均可换为\033;echo -e "\033[1;30m 黑色字 \033[0m"
背景颜色效果图:
综上:不同的字体和背景色的组合,可以得到多种多样的结果。
9.4 case语句企业级生产案例
9.4.1 传参方式添加VPN用户
范例9-7:实现通过传参的方式往/etc/openvpn_authfile.conf里添加用户,具体要求如下。
1)命令用法为:USAGE: sh adduser {-add|-del-search} username
2)传参要求为:参数为-add,表示添加后面接的用户名。参数为-del,表示删除后面接的用户名。参数为-search,表示查找后面接的用户名。
3)如果有同名的用户,则不能添加,如果没有对应的用户,则无需删除,查找到用户或没有用户时应给出明确提示。
4)/etc/openvpn_authfile.conf不能被所有外部用户直接删除及修改。
参考代码:
[root@zabbix 0509]# cat add_openvpn_user.sh
#!/bin/bash
. /etc/init.d/functions
FILE_PATH=/tmp/openvpn_authfile.conf
[ -f $FILE_PATH ] || touch $FILE_PATH
function usage(){
cat <<- zfd
USAGE:`basename $0` {-add|-del|-search} username
zfd
}
if [ $UID -ne 0 ] ;then
echo "you are not super user,please call root."
exit 1;
fi
if [ $# -ne 2 ];then
usage
exit 2
fi
case "$1" in
-a|-add)
shift
if grep "^$1$" ${FILE_PATH} &>/dev/null ## grep 精确查找
then
action $"vpnuser,$1 is exist" /bin/false
exit
else
chattr -i ${FILE_PATH} ## 解锁
/bin/cp ${FILE_PATH} ${FILE_PATH}.$(date +%F%T)
echo "$1" >>${FILE_PATH}
[ $? -eq 0 ] && action $"Add $1" /bin/true
chattr +i ${FILE_PATH} ## 加锁
fi
;;
-d|-del)
shift
if [ `grep "\b$1\b" ${FILE_PATH}|wc -l` -lt 1 ] ## grep 精确查找
then
action $"vpnuser,$1 is not exist."
exit
else
chattr -i ${FILE_PATH}
sed -i "/^${1}$/d" ${FILE_PATH}
[ $? -eq 0 ]&& action $"Del $1" /bin/true
chattr +i ${FILE_PATH}
exit
fi
;;
-s|-search)
shift
if [ `grep -w "$1" ${FILE_PATH} |wc -l` -lt 1 ] ## grep 精确查找
then
echo $"vpnuser,$1 is not exist."
else
echo $"vpnser,$1 is exist."
exit
fi
;;
*)
usage
exit
;;
esac
grep精确过滤单词的三种方法:
grep "^word$" $FILENAME
grep "\bword\b" $FILENAME
grep -w "word" $FILENAME
9.4.2 实现Nginx服务启动及关闭的功能
已知Nginx Web服务的管理命令如下:
启动服务命令为/application/nginx/sbin/nginx
停止服务命令为/application/nginx/sbin/nginx -s stop
请用case语句开发脚本,以实现Nginx服务启动及关闭的功能,
具体脚本命令为/etc/init.d/nginxd {start|stop|restart},并实现通过chkconfig进行开机自启动的管理。
解题思路:
1)先判断Nginx的PID文件是否存在(Nginx服务正常启动后PID文件就会存在),如果不存在,即表示Nginx没有运行,则运行Nginx服务的启动命令(可以把此部分写成start函数)。待要停止时,如果PID存在,就运行Nginx服务停止命令,否则就不运行停止命令(可以把此部分写成stop函数)。
2)通过脚本传入参数start或stop等,通过case语句获取参数进行判断。
3)为了看起来更专业,这里采用前文讲解的系统函数库functions中的action函数。
4)对函数及命令运行的返回值进行处理,使脚本看起来更专业、规范。
5)通过chkconfig来管理Nginx脚本,实现开机自启动。
参考代码(以centos6系列为例):
chmod +x /etc/init.d/nginxd
cat /etc/init.d/nginx.d
#!/bin/bash
path=/application/nginx/sbin
pid=/application/nginx/logs/nginx.pid
RETVAL=0
. /etc/init.d/functions
start(){
if [ ! -f $pid ];then
$path/nginx
RETVAL=$?
if [ $RETVAL -eq 0 ];then
action $"nginx is started." /bin/true
return $RETVAL
else
action $"nginx start faild." /bin/false
return $RETVAL
fi
else
echo "nginx is running."
return 0
fi
}
stop(){
if [ -f $pid ];then
$path/nginx -s stop
RETVAL=$?
if [ $RETVAL -eq 0 ];then
action $"nginx is stopped" /bin/true
return $RETVAL
else
action $"nginx stop failed. " /bin/false
return $RETVAL
fi
else
echo "nginx not running."
return $RETVAL
fi
}
case "$1" in
start)
start
RETVAL=$?
;;
stop)
stop
RETVAL=$?
;;
restart)
restart
RETVAL=$?
;;
*)
echo $"USAGE: $0 {start|stop|restart}"
exit 1
esac
exit $RETVAL
加入开机自启动,命令如下:
chkconfig --add nginxd
chkconfig --list nginxd
9.5 case条件语句的Linux系统脚本规范
9.6 总结
-
case语句和if条件语句的适用性
case语句比较适合变量值较少且为固定的数字或字符串集合的情况,如果变量的值是已知固定的start/stop/restart等元素,那么采用case语句来实现就比较适合。 -
case语句和if条件语句的常见应用场景
case主要是写服务的启动脚本,一般情况下,传参不同且具有少量的字符串,其适用范围较窄。
if就是取值判断、比较,应用面比case更广。几乎所有的case语句都可以用if条件语句来实现。 -
case语句的特点及优势
case语句就相当于多分支的if/elif/else语句,但是case语句的优势是更规范、易读。 - 特别说明:查看第9章的核心脚本代码http://oldboy.blog.51cto.com/2561410/1855461