Shell学习笔记(13)-流程控制之函数

函数声明
    语法1
    function 函数名称(){
        命令区域
    }
    语法2
    函数名称(){
        命令区域
    }
    语法3
    function 函数名称{
        命令区域
    }
函数调用
    函数名称
    函数名称 参数1 参数2 参数3
示例

    #! /bin/bash

    getline(){
        local i=0
        while read line
        do
            let ++i
        done < $file
        echo "$file共有$i行"
    }

    file=$1

    getline

    echo 'getline执行完毕'

    注:(1) local用来设定变量i是getline函数中专有的变量,不影响Script其他地方也叫i的变量
       (2) 必须在调用之前声明函数

函数取消
    unset -f getline
函数的结束状态
    执行函数时,函数中最后一个命令的传回值代表函数的结束状态。执行函数,如果遇到return命令,就立即结束,回到调用函数的下一个命令,此时函数的传回值为0。
    示例如下:
    #! /bin/bash

    getline(){
        local i=0
        while read line
        do
            let ++i
            if (( $i > 10 )); then
                echo "已超过10行了,不再继续读取."
                return
            fi
        done < $file
        echo "$file共有$i行"
    }

    file=$1

    getline

    echo $? //输出0

    echo 'getline执行完毕'

    函数也可以返回不同的返回值,见下列脚本:
    #! /bin/bash

    getline(){
        local i=0
        while read line
        do
            let ++i
            if (( $i > 10 )); then
                return 3
            fi
        done < $file
        echo "$file共有$i行"
    }

    file=$1

    getline

    if [ $? -eq 3 ]; then
        echo '行数过多,放弃读取.'
    else
        echo 'getline执行完毕'
    fi

函数与变量的作用范围
    函数仅在定义的Shell环境中有效,Bash执行环境时,并不会另外再开启一个子Shell.
    如果要传递函数给子Shell环境使用,可使用内置命令export和-f选项,语法如下:
        export -f 函数名称
    这样,getline就变成环境变量的一部分(以函数型存在),可供子Shell的Script调用。

    函数中使用内置命令local,设定变量i的属性为函数私有,变量i的作用范围则受到限制,仅在getline里面才有效。也就是说函数内部的i和函数外部叫i的变量是完全不同的(占用不同的变量空间)。
    不用local声明的变量则为全局变量.

    示例:
    #! /bin/bash

    myfun()
    {
        local v
        echo "$FUNCNAME中的变量v = $v"
        v=888
        echo "$FUNCNAME中的变量v = $v"
    }

    v=999
    myfun
    echo "主程序中的变量v = $v"

    执行结果:
    myfun中的变量v =
    myfun中的变量v = 888
    主程序中的变量v = 999

位置参数
    “位置参数”的使用方法很简单.$0代表Script文件名,$1代表第一个位置参数,$2代表第二个,$#代表参数的个数,$@代表所有以空白隔开的参数,$*代表所有参数所组成的字符串
    示例:
    #! /bin/bash

    #把$2的内容转向附加到$1指定的文件中
    appendfile(){
        echo "$2" >> "$1"
    }

    Dir=~/logs
    OutFile="$Dir/tmp.txt"

    #如果目录不存在,则开新目录
    [ -e $Dir ] || mkdir -p $Dir

    appendfile $OutFile "函数也可以这样用"
    appendfile $OutFile "这是函数的另一种用法"
    appendfile $OutFile "Over."

移动位置参数值(shift)和重置位置参数值(set)详见文档

取用命令行的选项和参数
    getopts 选项行 选项变量
    (1) u:ah 表示命令参数含有如下选项 -u -a -h,因为u:说明 -u后面必须提供额外的参数  如 -u Jack -a -h
    如果某一个选项字符后方,接上:,则表示该选项需要提供一个参数,如这里的u后面有:。如果执行Script时,选项u后方没有提供额外的参数,那么Bash会显示"option requires an arguments -- u“的错误信息。
    如果不想出现这种错误信息,可在选项行最前面加上:,例如:
    (2) :u:ah 像这样子,就算u后面没有参数,也不会产生错误信息.

    示例:
    #! /bin/bash

    while getopts u:ah opt
    do
        case $opt in
        u) echo "提供了选项u和参数: $OPTARG" ;;
        a) echo "提供了选项a" ;;
        h) echo "提供了选项h" ;;
        *) ;;
        esac
    done

建立函数库
    有一部分函数可以抽取出来,放在一个公共的文件中,形成函数库,在需要使用这些函数的shell脚本中,只须引用函数库就可以了,详细用法见文档。

递归函数
    示例:
    #! /bin/bash
    #
    #function也可以使用递归功能
    #以下是数学阶乘的计算,如5!= 5*4*3*2*1
    #

    function factor_in(){
        local tmp
        local tmp1

        #tmp 存储传入函数的整数值
        tmp="$1"

        #如果传入的整数是1,就显示1就好,总乘积r=1
        if [ $tmp -eq 1 ]; then
            echo -n " 1 "
            r=1
        else
            echo -n " $tmp * "
            tmp1=$tmp
            tmp=$(($tmp-1))
            factor_in $tmp
            r=$(($tmp1 * $r))
        fi
    }

    if [ $# -ne 1 ]; then
        echo "使用法:$0正整数"
        exit 1
    fi

    echo
    echo -n $1"! = "
    factor_in $1
    echo -n "= $r"
    echo


综合实例

    #! /bin/bash

    shopt -s -o nounset

    m=

    function GetLOTO(){
        local r

        r=$(( $RANDOM % 43 ))

        if [ $r -eq 0 ]; then
            r=$[ r + 1 ]
        fi

        if [ $r -le 9 ]; then
            echo "0$r"
        else
            echo $r
        fi
    }

    function GenNumAndCheckRepeat(){
        local n
        
        m=$({ GetLOTO; GetLOTO; GetLOTO; GetLOTO; GetLOTO; GetLOTO; } | sort -n)

        n="$m"

        n=$(echo $n | tr ' ' '\n' | uniq -d)

        if [ -z "$n" ]; then
            return 0
        else
            return 1
        fi
    }

    #主程序区
    if [ $# -ne 1 ]; then
        echo "使用法: $0组数"
        exit
    fi

    if [ "$1" -lt 1 -o "$1" -gt 99 ]; then
        echo "使用法: $0 [1-99]组"
        exit
    fi

    declare -i i=1 j
    while [ $i -le "$1" ]
    do
        GenNumAndCheckRepeat

        if [ $? -ne 0 ]; then
            continue
        fi

        j=$i
        if [ $j -le 9 ]; then
            echo -n "第0$j组:"
        else
            echo -n "第$j组:"
        fi

        echo $m

        i=$[ i + 1 ]
    done

你可能感兴趣的:(Shell学习笔记(13)-流程控制之函数)