返回顶部

zhangfd

个人博客,仅供学习使用

导航

shell编程 09 --- case条件语句的应用实践

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"
 红色字 

在上述命令中:

  1. echo -e可以识别转义字符,这里将识别特殊字符的含义,并输出。
  2. \E可以使用\033替代。
  3. “[1”数字1表示加粗显示(可以加不同的数字,以代表不同的意思,详细信息可用man console_codes获得)。
  4. 31m表示为红色字体,可以换成不同的数字,以代表不同的意思。
  5. “红色字oldboy”表示待设置的内容。
  6. “[0m”表示关闭所有属性,可以换成不同的数字,以代表不同的意思。

有关ANSI控制码的说明如下。

  1. \33[0m 表示关闭所有属性。
  2. \33[1m 表示设置高亮度。
  3. \33[4m 表示下划线。
  4. \33[5m 表示闪烁。
  5. \33[7m 表示反显。
  6. \33[8m 表示消隐。
  7. \33[30m -- \33[37m 表示设置前景色。
  8. \33[40m -- \33[47m 表示设置背景色。

console codes的更多知识可以参考man console_codes

热身实例见上文8.5.2-if实现

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 总结

  1. case语句和if条件语句的适用性
    case语句比较适合变量值较少且为固定的数字或字符串集合的情况,如果变量的值是已知固定的start/stop/restart等元素,那么采用case语句来实现就比较适合。
  2. case语句和if条件语句的常见应用场景
    case主要是写服务的启动脚本,一般情况下,传参不同且具有少量的字符串,其适用范围较窄。
    if就是取值判断、比较,应用面比case更广。几乎所有的case语句都可以用if条件语句来实现。
  3. case语句的特点及优势
    case语句就相当于多分支的if/elif/else语句,但是case语句的优势是更规范、易读。
  4. 特别说明:查看第9章的核心脚本代码http://oldboy.blog.51cto.com/2561410/1855461

posted on 2020-05-09 10:46  zhangfd  阅读(501)  评论(0编辑  收藏  举报