; bash脚本编程之select语句、函数 | Linux运维部落

bash脚本编程之select语句、函数

概述

    承接上篇,继续介绍一下另一个循环语句select,还有脚本中函数的相关内容,分为三个部分:

        1、select语句的介绍和效果演示

        2、脚本函数详解

        3、函数效果举例

第一章    select语句的介绍和效果演示

    1、select 循环与菜单格式

        select VAR in LIST;do

            循环体命令

        done

        select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入

        用户输入菜单列表中的某个数字,执行相应的命令

        用户输入被保存在内置变量 REPLY 中

    2、select 与 case

        select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c退出循环

        select 经常和 case 联合使用

        与 for 循环类似,可以省略 in list , 此时使用位置参量

    3、selcet应用举例

    blob.png blob.png

    blob.png blob.png

    blob.png blob.png

    4、补充:脚本执行时几种执行方式的区别

        .和source来执行脚本与bash 和给脚本执行权限执行的区别:

            . 和source执行脚本时:没有开子进程执行脚本,相当于直接在shell里面运行脚本里面的语句,故运行完脚本,脚本里面的变量在shell里依然有效

            bash或执行权限执行脚本:开了个子进程执行脚本,故脚本里面定义的变量,无法在shell里面继续生效

第二章    脚本中函数详解

    1、函数的基本概念

        函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。

        它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。

        注意:定义函数的代码段不会自动执行,在调用时才执行

        

    2、函数和shell程序比较相似,区别在于:

        Shell程序在子Shell中运行

        而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改

        函数在脚本中,相当于在脚本中插入了一段代码,所以函数并不是在脚本的shell中又开一个子shell执行函数,而是跟脚本shell在同一个shell中

    3、函数的定义:

        语法一:

             function FUNCTION_NAME {

                  函数体

                }

        语法二:

              FUNCTION_NAME() {

                  函数体

                }

 

        函数的定义位置:
            可在交互式环境下定义函数
            可将函数放在脚本文件中作为它的一部分
            可放在只包含函数的单独文件中

    4、函数的调用

        在代码中给定函数名即可,函数名出现的任何位置,在代码执行时,都会被自动替换为函数代码

        函数的生命周期:被调用时创建,返回时终止

        可以将经常使用的函数存入函数文件,然后将函数文件载入shell。文件名可任意选取,但最好与相关任务有某种联系。例如: functions.main,一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数。若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件

        载入文件的方式:.  FILENAME或source FILENAME

    5、函数的返回值

        函数有两种返回值:
            函数的执行结果返回值:

            <1> 使用echo或printf命令进行输出

            <2> 函数体中调用命令的输出结果
        函数的退出状态码:

            <1> 默认取决于函数中执行的最后一条命令的退出状态码

            <2> 自定义退出状态码, 其格式为:

                return 从函数中返回,用最后状态命令决定返回值

                    return 0 无错误返回。

                    return 1-255 有错误返回

        return其功能与脚本中exit的功能类似,在函数运行的任何地方,出现return即代表函数终止,即便return的位置不是最后一行,也会退出整个函数,功能与脚本的exit一样,脚本中一旦遇到exit,就退出脚本的运行

    6、删除函数

        unset命令完成此功能.命令格式为:unset FUNCTION_NAME

    7、函数中的参数

        函数可以接受参数:
            传递参数给函数:调用函数时,在函数名后面以空白分隔,给定参数列表即可;例如  FUNCTION_NAME arg1 arg2 …
        在函数体中当中,可使用$1, $2, …调用这些参数;还可以使用$@, $*, $#等特殊变量

    8、函数中的变量

        变量作用域:
            环境变量:当前shell和子shell有效
            本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数。
            局部变量:函数的生命周期;函数结束时变量被自动销毁

        

            定义局部变量的方法:在函数体中,使用local VAR=VALUE

                这样定义之后,该变量的作用范围就仅仅在函数体内部生效,函数结束,则变量不会影响后续脚本中变量的运行

        注意:如果函数中有局部变量,如果其名称同本地变量, 使用局部变量

    9、函数的递归

        函数的递归:函数直接或间接调用自身

         例如:数学中的阶乘

              N!=N*(N-1)!=N*(N-1)*(N-2)!=…

         这样就可以用函数的递归进行计算

         jc() {

              if [ $1 -eq 0 -o $1 -eq 1 ];then

                  echo 1

              else 

                  echo "$[$1*`jc $[$1-1]`]"

              fi

         }

         例如:斐波那契数列

         1,1,2,3,5,8,13,21…

         第一个值为1,第二个值为1,随后的每一个值都为其前两个数字之和

         求斐波那契数列的第N个数字是多少:(N-1)+(N-2)

         fblq() {

              if [ $1 -eq 1 -o $1 -eq 2 -o $1 ];then

                  echo 1

              else

                  echo "$[`fblq $[$1-1]`+`fblq $[$1-2]`]"

             fi

         }

第三章    函数效果举例

    1、编写服务脚本/root/bin/testsrv.sh,完成如下要求

        (1) 脚本可接受参数:start, stop, restart, status

        (2) 如果参数非此四者之一,提示使用格式后报错退出

        (3) 如是start:则创建/var/lock/subsys/SCRIPT_NAME, 并显示“启动成功”

            考虑:如果事先已经启动过一次,该如何处理?

        (4) 如是stop:则删除/var/lock/subsys/SCRIPT_NAME, 并显示“停止完成”

            考虑:如果事先已然停止过了,该如何处理?

        (5) 如是restart,则先stop, 再start

            考虑:如果本来没有start,如何处理?

        (6) 如是status, 则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAMEis running…”如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped…”其中:SCRIPT_NAME为当前脚本名

        (7)在所有模式下禁止启动该服务,可用chkconfig 和 service命令管理

    #!/bin/bash    
    # Autor: nwc
    # Version: 2.0
    # CreateTime: 2016-08-19
    # Description:
    # 关于第7条的实现,考虑可以将脚本放到/etc/init.d目录下,在脚本开头注释段标明“# chkconfig:运行级别  启动优先级  关闭优先级”    # 然后运行chkconfig  --add 脚本名 --level 指定哪些级别开机启动
    
    FILE=/tmp/$0
    
    START() {
            if [ -f $FILE ];then
                    echo "$0 has been start"        
            else
                    touch $FILE && echo "Start success" || echo "Start fail"
            fi
    }
    
    STOP() {
            if [ -f $FILE ];then
                    rm -rf $FILE && echo "Stop success" || echo "Stop fail"
            else
                    echo "$0 has been stopped"
            fi
    }
    
    RESTART() {
            STOP
            START
    }
    
    STATUS() {
            [ -f $FILE ] && echo "$0 is running..." || echo "$0 is stopped..."
    }
    
    
    read -p "Please input you choice start|stop|restart|status:  " CH
    
    case $CH in
    start)
            START
    ;;
    
    stop)
            STOP
    ;;
    
    restart)
            RESTART
    ;;
    
    status)
            STATUS
    ;;
    
    *)
            echo "bad choice..."
    ;;
    esac

    执行效果如下:

    blob.png

    blob.png

    2、编写脚本/root/bin/copycmd.sh

        (1) 提示用户输入一个可执行命令名称;

        (2) 获取此命令所依赖到的所有库文件列表

        (3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;

            如:/bin/bash ==> /mnt/sysroot/bin/bash

                /usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd

        (4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:

            如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2

        (5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit退出

    #!/bin/bash    
    # Autor: nwc
    # Version: 2.0
    # CreateTime: 2016-08-19
    # Description:
    
    CMDCP() {
            DIR=`dirname $CmdPath`
            if [ -d ${LuJing}${DIR} ] ;then
                    cp $CmdPath ${LuJing}${DIR} && echo "cp $CMD success" || echo "cp $CMD fail"
            else
                    mkdir -p ${LuJing}${DIR}
                    cp $CmdPath ${LuJing}${DIR} && echo "cp $CMD success" || echo "cp $CMD fail"
            fi    
    }
    
    CMDLIBCP() {   
            for i in ${LibCmd} ; do
                    LIBDIR=`dirname $i`
                    if [ -d ${LuJing}${LIBDIR} ];then
                            cp $i ${LuJing}${LIBDIR} && echo "cp $i success" || echo "cp $i fail" 
                    else
                            mkdir -p ${LuJing}${LIBDIR}
                            cp $i ${LuJing}${LIBDIR} && echo "cp $i success" || echo "cp $i fail" 
                    fi
            done
    }
    
    
    while true;do
         read -p "Input a exec program name like ls/cat... q for quit  " CMD
            case $CMD in
            q)
                    echo "exit..."
                    exit
            ;;
            *)
                    if which --skip-alias $CMD &>/dev/null  && [[ $CMD != "q" ]]; then
                            CmdPath=`which --skip-alias $CMD`
                            LibCmd=`ldd $CmdPath|grep -o -E "/[^[:space:]]+"`
                            LuJing=/tmp/command
                            CMDCP
                            CMDLIBCP
                    else
                             echo "you input is not a right command"
                                    continue
                    fi
            ;;
            esac
    done

      执行效果如下:

    blob.png

    blob.png  

    blob.png

    blob.png

    blob.png

    blob.png

    

原创文章,作者:M20-1倪文超,如若转载,请注明出处:/37714

评论列表(1条)

  • 马哥教育
    马哥教育 2016-08-22 12:04

    总结的很详细,作业也完成的很用心,关于shell脚本主要是多抽时间写,看,学习别人的思想,只有养成了编程的思想,才能写出优秀的代码。

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1660809109@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班

友情链接:万达直属  万达娱乐主管  万达招商QQ  万达娱乐开户  万达娱乐主管  万达娱乐注册  万达登录  万达娱乐主管QQ  万达主管QQ  万达娱乐招商