zoukankan      html  css  js  c++  java
  • shell编程 11 --- for 和 select 循环语句的应用实践

    shell编程 11 --- for和select循环语句的应用实践


    for循环语句和while循环语句类似,但for循环语句主要用于执行次数有限的循环,
    而不是用于守护进程及无限循环。for循环语句常见的语法有两种。


    11.1 for循环语句结构

    第一种for循环语句为变量取值型,语法结构如下:

    for 变量名 in 变量取值列表
    do
    	指令...
    done
    # 在此结构中“in变量取值列表”可以省略,省略时相当于in“$@”,
    # 也就是使用for i就相当于使用for i in“$@”。
    

    在这种for循环语句语法中,for关键字后面会有一个“变量名”,变量名依次获取in关键字后面的变量取值列表内容(以空格分隔),每次仅取一个;
    然后进入循环(do和done之间的部分)执行循环内的所有指令,当执行到done时结束本次循环;
    之后,“变量名”再继续获取变量列表里的下一个变量值,继续执行循环内的所有指令,当执行到done时结束返回;
    以此类推,直到取完变量列表里的最后一个值并进入循环执行到done结束为止。


    第二种for循环语句称为C语言型for循环语句,其语法结构如下:

    for ((exp1;exp2;exp3))
    do
    	指令...
    done
    

    for关键字后的双括号内是三个表达式,第一个是变量初始化(例如:i=0),
    第二个为变量的范围(例如:i<100),第三个为变量自增或自减(例如:i++)。
    当第一个表达式的初始化值符合第二个变量的范围时,就进入循环执行;
    当条件不满足时就退出循环。


    [root@zabbix ~]# cat for_1.sh 
    for ((i=1;i<=3;i++))
    do
        echo $i
    done 
    

    范例11-1:for和while循环的对比

    [root@zabbix 0511]# cat while_1.sh 
    i=1
    while ((i<=3))
    do
        echo $i
       ((i++))
    done
    

    特别说明:

    1)如果希望程序持续运行,则多用while,包括守护进程。

    2)如果是有限次循环,则多用for,实际工作中使用for的机会更多。

    11.2 for循环语句的基础实践

    11.2.1 竖向打印数字

    范例11-2:竖向打印5、4、3、2、1这5个数字。

    参考答案1:直接列出元素的方法。

    [root@zabbix 0511]# cat for_num.sh 
    for num in 5 4 3 2 1
    do
        echo $num
    done
    

    参考答案2:利用大括号{}生成数字序列的方法。

    [root@zabbix 0511]# echo {5..1}
    5 4 3 2 1
    [root@zabbix 0511]# cat for_num.sh 
    for num in {5..1}
    do
        echo $num
    done
    

    参考答案3:采用seq生成数字序列的用法(这里先简略介绍,后文有细讲)。

    for num in {5..1}
    do
        echo $num
    done
    

    11.2.2 打印输出当前目录下文件名

    范例11-3:获取当前目录下的目录或文件名,并将其作为变量列表打印输出。

    模拟数据如下:

    [root@zabbix 0511]# mkdir -p /test/{test.txt,oldboy.txt,oldgirl.rxt}
    [root@zabbix 0511]# ll /test/
    total 0
    drwxr-xr-x 2 root root 6 May 11 14:52 oldboy.txt
    drwxr-xr-x 2 root root 6 May 11 14:52 oldgirl.rxt
    drwxr-xr-x 2 root root 6 May 11 14:52 test.txt
    [root@zabbix 0511]#
    

    实现代码如下:

    [root@zabbix 0511]# cat for_file.sh 
    cd /test
    for filename in `ls`
    do
        echo $filename
    done
    

    11.2.3 批量修改文件扩展名

    范例11-4:用for循环批量修改文件扩展名(把txt改成jpg)。

    [root@zabbix 0511]# touch /test/{oldboy.txt,oldgirl.txt,test.txt}
    [root@zabbix 0511]# ls /test/
    oldboy.txt  oldgirl.txt  test.txt
    [root@zabbix 0511]# cat for_ext.sh
    #!/bin/bash
    cd /test
    for filename in `ls|grep "txt$"`
    do
        mv $filename `echo $filename|cut -d . -f1`.gif
    done
    [root@zabbix 0511]# sh for_ext.sh 
    [root@zabbix 0511]# ls /test/
    oldboy.gif  oldgirl.gif  test.gif
    

    实际上,本题还有更简单的实现方法,即通过rename命令来直接实现,如下:

    [root@zabbix test]# ls
    oldboy.gif  oldgirl.gif  test.gif
    [root@zabbix test]# rename "gif" "txt" *.gif
    [root@zabbix test]# ls
    oldboy.txt  oldgirl.txt  test.txt
    

    11.3 for循环语句的企业案例

    11.3.1 在Linux下批量修改文件名

    范例11-5:在Linux下批量修改文件名,将文件名中包含的“_finished”去掉。

    提示:通过此题的解答可以学习到sed、awk、rename、mv等命令的实战应用。

    本题的基本解题思路和范例11-4类似,先进行单个文件的改名,然后再用循环实现批量改名,这也是最常规的做法,
    当然,还可以用专业的改名工具rename来处理(本节主要是学习for循环知识)。

    参考代码如下:

    [root@zabbix test]# cat for_file.sh 
    #!/bin/bash
    cd /test
    touch stu_10246_{1..5}_finished.jpg
    ls *finished*
    for filename in `ls *finished*`
    do
        mv $filename `echo $filename |sed 's/_finished//g'`
    done
    

    其余方法实现:

    1. ls + awk + bash 实现
    ls |awk -F "." '{print "mv " $0,$1"_finished."$2}'|bash
    
    1. 专业命令rename实现
    rename "_finished" "" *jpg
    

    11.3.2 打印九九乘法表

    范例11-8:打印九九乘法表,实现图形如图11-3所示。

    参考代码:

    [root@zabbix 0511]# cat for_nn.sh 
    #!/bin/bash
    ## 添加背景色:白底黑字
    COLOR='e[47;30m'
    RES='e[0m'
    for ((i=1;i<=9;i++))
    do
        for ((j=1;j<=i;j++))
        do
    	if [ `echo $((${j}*${i}))` -le 9 ];then
    	  echo -en "${COLOR}${j}x${i}=$((${j}*${i})) ${RES}	"  ## 格式控制
    	else
    	  echo -en "${COLOR}${j}x${i}=$((${j}*${i}))${RES}	"	## 格式控制
    	fi
        done
        echo
    done
    

    11.3.3 计算从1加到100之和(用C的for)

    1. for循环实现:
    [root@zabbix 0511]# cat for_oneto100.sh 
    sum=0
    for ((i=1;i<=100;i++))
    do
        ((sum=sum+i))
    done
    echo $sum
    
    1. while循环实现:
    [root@zabbix 0511]# cat while_oneto100.sh 
    i=1
    sum=0
    while ((i<=100))
    do
        ((sum=sum+i))
        ((i++))
    done
    echo $sum
    
    1. 公式法实现:n*(n+1)/2
    [root@zabbix 0511]# echo $((100*(1+100)/2))
    5050
    

    11.4 for循环语句的企业高级实战案例

    11.4.1实现MySQL分库备份的脚本

    范例11-11:实现MySQL分库备份的脚本。

    第一步:批量创建数据库

    ​ 基本的批量建库脚本如下,这里使用for循环在数据库服务器里批量创建数据库。

    [root@zabbix 0511]# cat for_createDBs.sh
    #!/bin/bash
    Path_mysql="/application/mysql/bin:$PATH"
    MYUSER=root
    MYPASS=oldboy123
    SOCKET=/data/3306/mysql.sock
    MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET"
    for dbname in oldboy oldgirl moox shiban web
    do
    	$MYCMD -e "create database $dbname"
    done
    ## 说明:不登录数据库创建数据库的命令为
    ## mysql -uroot -poldboy123 -S /data/3306/mysql.sock -e"create database oldboy; "
    

    第二步:分库备份

    ​ 分库备份数据库(即每个库一个文件)的命令如下:

    [root@zabbix 0511]# cat for_dumpDBs.sh
    #!/bin/bash
    Path_mysql="/application/mysql/bin:$PATH"
    PATH_BACKDB=/server/backup
    MYUSER=root
    MYPASS=oldboy123
    SOCKET=/data/3306/mysql.sock
    MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET"
    MYDUMP="mysqldump -u$MYUSER -p$MYPASS -S $SOCKET"
    [ -d $PATH_BACKDB ] || mkdir -p $PATH_BACKDB
    for dbname in `$MYCMD -e "show databases;"|sed '1,2d'|egrep -v "mysql|schema"`
    do
    	$MYDUMP $dbname|gzip >$PATH_BACKDB/${dnbame}_$(date +%F-%T).tar.gz
    done
    ## 说明:备份数据库的命令为
    mysqldump -uroot -poldboy123 -S /data/3306/mysql.sock oldboy |gzip>/server/backup/oldboy_$(date +%F).sql.gz。
    

    11.4.2 实现MySQL分库分表备份的脚本

    范例11-12:实现MySQL分库分表备份的脚本。

    第一步:准备测试数据:通过写脚本批量建表并插入数据

    [root@zabbix 0511]# cat for_createTBs.sh
    #!/bin/bash
    Path_mysql="/application/mysql/bin:$PATH"
    MYUSER=root
    MYPASS=oldboy123
    SOCKET=/data/3306/mysql.sock
    MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET"
    for dbname in oldboy oldgirl moox shiban web
    do
    	$MYCMD -e "use $dbname;create teble test(id int,name varchar(16));insert into test values(1,'testdata');"
    done
    

    第二步:使用脚本查看测试数据结果:

    [root@zabbix 0511]# cat for_selectTBs.sh
    #!/bin/bash
    Path_mysql="/application/mysql/bin:$PATH"
    MYUSER=root
    MYPASS=oldboy123
    SOCKET=/data/3306/mysql.sock
    MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET"
    for dbname in oldboy oldgirl moox shiban web
    do
    	echo "======== ${dbname}.test ============" 
    	$MYCMD -e "use $dbname;select * from ${dbname}.test;"
    done
    

    第三步:最终形成脚本

    [root@zabbix 0511]# cat for_dumpDBs_TBs.sh
    #!/bin/bash
    Path_mysql="/application/mysql/bin:$PATH"
    PATH_BACKDB=/server/backup
    MYUSER=root
    MYPASS=oldboy123
    SOCKET=/data/3306/mysql.sock
    MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET"
    MYDUMP="mysqldump -u$MYUSER -p$MYPASS -S $SOCKET"
    [ -d $PATH_BACKDB ] || mkdir -p $PATH_BACKDB
    for dbname in `$MYCMD -e "show databases;"|sed '1,2d'|egrep -v "mysql|schema"`
    do
    	PATH_table=`mkdir -p $PATH_BACKDB/${dbname}_$(date +%F)`
    	for table in `$MYCMD -e "show tables from $dbname;"|sed '1d'`
    	do
    		$MYDUMP $dbname $table |gzip > $PATH_table/${dbname}_${table}.sql.gz
    	done
    done
    

    11.4.3 批量检查Web服务并邮件报警

    例11-13:在生产环境下批量检查Web服务是否正常,并且发送相关邮件或手机报警信息。

    [root@zabbix 0512]# cat for_web.sh 
    #!/bin/bash
    MYPATH=/server/scripts
    MAIL_GROUP="2144865225@qq.com 3321322512@qq.com"
    PAGER_GROUP="10086 10010"
    LOG_FILE="/tmp/web_check.log"
    
    [ -d $MYPATH ] || mkdir -p $MYPATH
    function UrlList(){
        cat >$MYPATH/domain.list<<-zfd
        http://blog.moox.com
        http://bbs.moox.com
        http://www.moox.com
        http://www.baidu.com
        http://172.16.1.71
    zfd
    }
    function CheckUrl(){
        FAILCOUNT=0
        for ((i=1;i<=3;i++))
        do
    	wget -T 5 --tries=1 --spider $1 &>/dev/null
    	if [ $? -ne 0 ];then
    	    let FAILCOUNT+=1
    	else
    	    break
    	fi
        done
        return $FAILCOUNT
    }
    function MyMail(){
        local SUBJECT_CONTENT=$1
        for MAIL_USER in `echo $MAIL_GROUP`
        do
    	mail -s "$SUBJECT_CONTENT" $MAIL_USER < $LOG_FILE
        done
    }
    function MyPager(){
        for PAGER_USER in `echo $PAGER_GROUP`
        do
    	TITLE=$1
    	CONTACT=$PAGER_USER
    	HTTPGW=http://oldboy.sms.cn/smsproxy/sendsms.action
    	curl -d cdkey=5ADF-EFA -d password=OLDBOY -d phone=$CONTACT -d message="$TITLE[$2]" $HTTPGW &>/dev/null
        done
    }
    function SendMsg(){
        ERRORS=$1
        echo "error count: $ERRORS "
        if [ $1 -ge 3 ];then
    	RETVAL=1
    	NOW_TIME=`date +"%Y-%m-%d %H:%M:%S"`
    	SUBJECT_CONTENT="http://$2 is error, ${NOW_TIME}"
    	echo -e "$SUBJECT_CONTENT"|tee $LOG_FILE 
    	MyMail $SUBJECT_CONTENT 2>/dev/null
    	MyPager $SUBJECT_CONTENT $NOW_TIME 2>/dev/null
        else
    	echo "http://$2 is ok."
    	echo "action:check err count:$1"
    	RETVAL=0
        fi
        return $RETVAL
    }
    function main(){
        UrlList
        for url in `cat $MYPATH/domain.list`
        do
    	echo "checking $url ..."
    	CheckUrl $url 
    	SendMsg $? $url
        done
    }
    main
    [root@zabbix 0512]# sh for_web.sh
    

    11.4.4 批量创建系统账号并设置密码

    范例11-14:批量创建10个系统账号(oldboy01-oldboy10),并设置密码(密码为随机数,要求是字符和数字的混合)。

    参考答案1:passwd无交互设置密码方式

    1)创建10个系统账号,即oldboy01~oldboy10。

    [root@zabbix 0512]# seq -s " " -w 10
    01 02 03 04 05 06 07 08 09 10
    [root@zabbix 0512]# echo {01..10}
    01 02 03 04 05 06 07 08 09 10
    

    2)要想通过脚本创建账号,必须知道如何实现无交互设置密码

    [root@zabbix 0512]# useradd oldgirl
    [root@zabbix 0512]# echo 123456|passwd --stdin oldgirl 
    Changing password for user oldgirl.
    passwd: all authentication tokens updated successfully.
    

    3)密码为随机数,并且是8位字符串

    RANDOM+md5sum方法

    [root@zabbix 0512]# echo $RANDOM|md5sum |cut -c 5-12
    f1139af0
    

    4)形成脚本,调用系统函数库让输出更美观,同时增强逻辑性

    [root@zabbix 0512]# cat for_useradd.sh 
    #!/bin/bash
    . /etc/init.d/functions
    user="oldboy"
    passfile="/tmp/user.log"
    for num in `seq -w 11 15`
    do
        useradd ${user}${num} &>/dev/null
        ##  提示:注意随机数的字符串要定义成变量,否则,每次执行结果都会不相同。
        pass="`echo $RANDOM |md5sum| cut -c 3-11`"
        echo "$pass"|passwd --stdin $user$num &>/dev/null
        echo -e "user: $user$num	 passwd: $pass" >>$passfile
        if [ $? -eq 0 ];then
    	action $"$user$num is OK" /bin/true
        else
    	action $"$user$num is failed" /bin/false
        fi
    done
    echo -----------------
    cat $passfile && >$passfile
    [root@zabbix 0512]# sh for_useradd.sh
    

    参考答案2:chpasswd命令方式设置密码

    1)按照参考答案1的思路正常创建账号。

    2)要批量创建密码,可使用chpasswd来实现,chpasswd是一个批量更新用户口令的工具。

    chpasswd命令介绍:

    ## 1. 单个创建用户并设置密码
    useradd oldgirl01
    echo "oldgirl01:123456"|chpasswd
    ## 2. 给多个用户修改密码
    [root@zabbix 0512]# for user in oldboy1{1..4};do userdel $user;done
    ## 说明:用户必须存在。
    [root@zabbix 0512]# for user in oldboy1{1..4};do useradd $user&>/dev/null;done
    [root@zabbix 0512]# cat /tmp/user.log  ## 用户名和密码之间不能有空格
    oldboy11:acd38594e
    oldboy12:8598c6699
    oldboy13:5b0f8388b
    oldboy14:863255424
    [root@zabbix 0512]# chpasswd </tmp/user.log 
    [root@zabbix 0512]# 
    

    shell实现脚本:

    [root@zabbix 0512]# > /tmp/user.log 
    [root@zabbix 0512]# cat for_useradd.sh 
    #!/bin/bash
    . /etc/init.d/functions
    user="oldboy"
    passfile="/tmp/user.log"
    for num in `seq -w 11 15`
    do
        useradd ${user}${num} &>/dev/null
        pass="`echo $RANDOM |md5sum| cut -c 3-11`"
        #echo "$pass"|passwd --stdin $user$num &>/dev/null
        echo -e "${user}${num}:$pass" >>$passfile
        if [ $? -eq 0 ];then
    	action $"$user$num is OK" /bin/true
        else
    	action $"$user$num is failed" /bin/false
        fi
    done
    echo -----------------
    chpasswd < $passfile
    cat $passfile && >$passfile
    

    11.5 Linux系统产生随机数的6中方法

    方法1:通过系统环境变量($RANDOM)实现,示例代码如下


    RANDOM的随机数范围为0~32767,因此,加密性不是很好,可以通过在输出的随机数后增加加密字符串
    》(就是和密码生成有关的一个字符串)的方式解决,最后再一起执行md5sum操作并截取结果的后n位,
    这样一来,就无法根据随机数范围0~32767来猜出具体结果了。


    [root@zabbix 0512]# echo $RANDOM
    1320
    [root@zabbix 0512]# echo $RANDOM
    14048
    [root@zabbix 0512]# echo $RANDOM|md5sum |cut -c 1-10
    a7bc8e8617
    

    方法2:通过openssl产生随机数,示例代码如下。


    令数字与大小写字符相结合,并且带上特殊字符,可以达到很长的位数,这样的随机数很安全。


    [root@zabbix 0512]# openssl rand -base64 60
    dtOjbwutVaZ6Wk7nCo/KOxqK7zWaYsaY582DW0FoMr2gYwGWhD02Hq1A4fGXJhtFVdE7D/9MUv3qAM8G
    

    方法3:通过时间(date)获得随机数,示例代码如下。

    [root@zabbix 0512]# date +%s%N
    1589265384941362238
    [root@zabbix 0512]# date +%s%N
    1589265392066253068
    

    方法4:通过/dev/urandom配合chksum生成随机数。


    /dev/random设备存储着系统当前运行环境的实时数据。它可以看作系统在某个时候的唯一值,
    因此可以用作随机数元数据。我们可以通过文件读取的方式,读到里面的数据。
    /dev/urandom这个设备的数据与random里的一样。只是,它是非阻塞的随机数发生器,读取操作不会产生阻塞。


    [root@zabbix 0512]# head /dev/urandom |cksum
    1773856086 2639
    [root@zabbix 0512]# head /dev/urandom |cksum
    2770058246 1782
    
    

    方法5:通过UUID生成随机数。


    UUID码全称是通用唯一识别码(Universally Unique Identifier, UUID),它是一个软件建构的标准,
    亦为自由软件基金会(Open Software Foundation, OSF)的组织在分布式计算环境(Distributed ComputingEnvironment, DCE)领域的一部分。

    UUID的目的是让分布式系统中的所有元素都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。
    如此一来,每个人都可以创建不与其他人发生冲突的UUID。在这样的情况下,就不需要考虑数据库创建时的名称重复问题了。
    它会让网络中任何一台计算机所生成的UUID码都是互联网整个服务器网络中唯一的编码。
    它的原信息会加入硬件、时间、机器当前运行信息等。


    [root@zabbix ~]# cat /proc/sys/kernel/random/uuid 
    49b37c77-6fe8-4854-9e43-6f76869fc0f7
    [root@zabbix ~]# cat /proc/sys/kernel/random/uuid 
    46ac7362-7754-451f-818b-20317e5ca3c8
    

    方法6:使用expect附带的mkpasswd生成随机数

    mkpasswd命令依赖于数据包expect,因此必须通过“yum install expect -y”命令先安装该数据包:

    [root@zabbix ~]# mkpasswd -l 9 -d 2 -c 3 -C 3 -s 1
    r1*X9BZyp
    [root@zabbix ~]# mkpasswd -l 9 -d 2 -c 3 -C 3 -s 1
    fH.96MKhl
    -- 参数:
    The -l 	: the length of the password. 		default is 9
    The -d 	: the number of digits, 			default is 2.
    The -c 	: the number of lowercase. 			default is 2
    The -C	: the number of uppercase,			default is 2
    The -s	: the number of special characters .default is 1.
    -- 上面的随机数长短不一,如何统一格式化呢?解答:使用md5sum命令。
    [root@zabbix ~]# mkpasswd -l 9 -d 2 -c 3 -C 3 -s 1|md5sum |cut -c 3-11
    535020bca
    

    11.6 select循环语句介绍及语法


    select循环语句的主要作用可能就是创建菜单,在执行带select循环语句的脚本时,
    输出会按照数字顺序的列表显示一个菜单项,并显示提示符(默认是#? ),
    同时等待用户输入数字进行选择,下面就来带大家看看生成菜单项的语法及具体案例实践。


    第一种: for循环语句为变量取值型,语法结构如下:

    select 变量名 [ in 菜单取值列表]
    do
    	指令...
    done
    

    提示:bash帮助语法显示:select name [ in word ]; do list; done

    在此结构中“in变量取值列表”可省略,省略时相当于使用in“(@”,使用for i就相当于使用for i in“)@”。

    与for循环不同点:

    select循环执行后会出现菜单项等待用户选择(不会自动循环所有变量列表),而用户输入的只能是菜单项前面的数字序号,
    每输入一次对应的序号就会执行一次循环,直到变量后面对应列表取完为止。

    select循环结构执行流程对应的逻辑图如图11-5所示。

    11.7 selec循环语句案例

    11.7.1 用select循环打印简单菜单项的多种实现方法

    1 select直接使用列表字符串

    [root@zabbix 0513]# cat select_1.sh 
    #!/bin/bash
    select name in oldboy oldgirl moox
    do
        echo $name
    done
    # 执行脚本后打印带数字序列(数字加右小括号)的菜单项,内容就是变量列表的内容
    [root@zabbix 0513]# sh select_1.sh 
    1) oldboy
    2) oldgirl
    3) moox
    #? 1		--- 必须输入序列号,输入错误则返回空,界面不是很优雅
    oldboy
    #? 2
    oldgirl
    #? 3
    moox
    #? 4
    

    2 select采用数组做变量列表

    [root@zabbix 0513]# cat select_arr.sh 
    #!/bin/bash
    array=(oldboy oldgirl moox)
    select name in "${array[@]}"
    do
        echo $name
    done
    [root@zabbix 0513]# sh select_arr.sh
    执行结果与上例一样
    

    3 select把命令结果作为变量列表(菜单项)

    (1)数据准备

    [root@zabbix 0513]# mkdir /tmp/test
    [root@zabbix 0513]# mkdir /tmp/test/{oldboy,oldgirl,moox}
    

    (2)脚本开发

    [root@zabbix 0513]# cat select_ls.sh 
    #!/bin/bash
    select name in  `ls /tmp/test`
    do
        echo $name
    done
    

    11.7.2 select打印菜单:提示符功能+web服务菜单实践


    通过上一个范例我们了解到,select循环菜单项的默认提示很不友好,
    并且输入的是数字,打印的变量值却是数字对应的菜单项内容。
    那能不能针对默认提示符以及打印输入内容进行调整呢?当然可以,且看下面的案例。


    范例11-16:调整select循环菜单项的默认提示符及利用select变量打印数字序号。

    [root@zabbix 0513]# cat select_menu.sh 
    #!/bin/bash
    PS3="please select a num from menu:"
    select name in oldboy oldgirl moox
    do
       echo -e "I guess you selected the num is:
     $REPLY) $name"
    done
    [root@zabbix 0513]# sh select_menu.sh 
    1) oldboy
    2) oldgirl
    3) moox
    please select a num from menu:4
    I guess you selected the num is:
     4)  								# == "$REPLY)"
    please select a num from menu:  	# == "PS3"
    
    

    本范例重点讲解了select循环的两个特殊变量,
    其中PS3系统环境变量用于控制select循环的提示符,
    REPLY变量用于获取菜单项对应的数字,也就是用户输入的数字。

    范例11-17:打印选择菜单,按照选择一键安装不同的Web服务。

    示例菜单:

    [root@zabbix 0513]# sh select_WebMenu.sh 
    	1.[install lamp]
    	2.[install lnmp]
    	3.[exit]
    	Please input the num you choose:
    

    要求:
    1)当用户输入1时,输出“start installing lamp.”提示,然后执行/server/scripts/lamp.sh,
    输出"lamp isinstalled"后退出脚本,这就是实际工作中所用的lamp一键安装脚本;

    2)当用户输入2时,输出“start installing lnmp.”提示,然后执行/server/scripts/lnmp.sh,
    输出"lnmp isinstalled"后退出脚本,这就是实际工作中所用的lnmp一键安装脚本;

    3)当输入3时,退出当前菜单及脚本;
    4)当输入任何其他字符时,给出提示“Input error”后退出脚本;
    5)要对执行的脚本进行相关的条件判断,
    例如:脚本文件是否存在,是否可执行等判断,尽量用上前面讲解的知识点。

    解答:本范例和范例6-36是一道题,但是采用的实现方法却完全不同,
    本例将采用select循环结构实现范例6-36脚本的升级版

    [root@zabbix 0513]# cat select_webInstall.sh 
    #!/bin/bash
    RETVAL=0
    path=/server/scripts
    [ ! -d "$path" ] && mkdir -p $path
    function Usage(){
        echo "USGE: $0 argv"
        return 1
    }
    function InstallService(){
        [ $# -ne 1 ] &&{
    		Usage
        }
        local RETVAL=0
        service=$1
        echo "start install $service ..."
        sleep 2
        if [ -x "$path/${service}.sh" ];then
    		$path/${service}.sh
    		return $RETVAL
        else
    		echo "$path/${service}.sh not exist or can not be exec."
    	return 1
        fi
    }
    function main(){
        PS3="Please input the num you choose: "
        select var in "Install lamp" "Install lnmp" "exit"
        do
    		case $var in
    	    	"Install lamp")
    				InstallService lamp
    				RETVAL=$?
    				;;
    	    	"Install lnmp")
    				InstallService lnmp
    				RETVAL=$?
    				;;
    	    	"exit")
    				echo bye.
    				return 3
    				;;
    	    	*)
    				echo "the num you input must be {1|2|3}"
    				echo "Input Error."
    		esac
        done
        exit $RETVAL
    }
    main
    ########################################################
    [root@zabbix 0513]# sh select_webInstall.sh 
    1) Install lamp
    2) Install lnmp
    3) exit
    Please input the num you choose: 1
    start install lamp ...
    lamp is installed
    Please input the num you choose: 2
    start install lnmp ...
    /server/scripts/lnmp.sh not exist or can not be exec.
    Please input the num you choose: 4
    the num you input must be {1|2|3}
    Input Error.
    Please input the num you choose: 3
    bye.
    [root@zabbix 0513]#
    

    将上述脚本中case部分使用系统变量REPLY实现改写:

    case $REPLY in
    	"1")
    		InstallService lamp
    		RETVAL=$?
    		;;
    	"2")
    		InstallService lnmp
    		RETVAL=$?
    		;;
    	"3")
    		echo bye.
    		return 3
    		;;
    	*)
    		echo "the num you input must be {1|2|3}"
    		echo "Input Error."
    esac
    
    
  • 相关阅读:
    阿蒂亚谈数学——我对《数学的统一性》的笔记
    陶哲轩实分析习题8.5.6
    陶哲轩实分析习题8.5.2
    陶哲轩实分析习题8.5.9
    陶哲轩实分析习题8.5.5
    陶哲轩实分析习题8.5.6
    陶哲轩实分析习题8.5.2
    陶哲轩实分析习题8.5.1
    陶哲轩实分析习题8.5.9
    陶哲轩实分析习题8.5.5
  • 原文地址:https://www.cnblogs.com/moox/p/12882128.html
Copyright © 2011-2022 走看看