shell浅谈之十函数

一、简介

       Linux Shell编程中也会使用到函数,函数可以把大的命令集合分解成若干较小的任务,也避免重复编写相同的代码。在Shell中,所有的函数定义都是平行的,即不允许在函数体内再定义其他的函数,但允许函数之间相互调用。函数又涉及到很多基本使用:函数参数调用、函数返回值、局部变量及全局变量、函数间的相互调用和函数递归调用。

二、详解

1、函数的定义

(1)函数是一串命令的集合,如果脚本中有重复代码时可以考虑使用函数,在shell中函数的返回值只能为退出状态0或1。应注意函数名在脚本中的唯一。可以在函数名前加上fuction关键字也可省略。函数体中的命令集合必须含有至少一条命令(函数不允许空命令,与C不同)。

(2)脚本遇到"hello(){"结构时,知道定义了一个名为hello的函数,而且它会记住hello代表的函数,并执行函数体中的命令,直到出现"}"字符结束,当执行到单独的行hello时,shell就知道应该去执行刚才定义的函数,执行完毕返回继续执行其他的命令或函数。在shell中不需要申明就可直接定义函数,但在调用函数前需对它进行定义。如下是shell脚本中循环调用函数的例子:

#function2.sh
#!/bin/bash

output()
{
     for(( num1 = 1; num1 <= 5; num1++ ))
     do
         echo -n "$num1 "
     done 
}

let "num2=1"
while [ "$num2" -le 5 ]
do
    output
    echo ""
    let "num2=num2 + 1"
done

(3)判断当前目录下存在多少个文件和子目录

#显示当前目录下文件和目录数
#function3.sh
#!/bin/bash

directory()
{
    let "filenum = 0"
    let "dirnum = 0"
    
    ls
    echo ""                 #echo换行
    
    for file in $( ls )     #for循环判断当前子目录和文件
    do
        if [ -d $file ]     #判断为子目录
        then
            let "dirnum = dirnum + 1"
        else                #判断为文件
           let "filenum = filenum + 1"
        fi
    done

    echo "The number of directory is $dirnum"
    echo "The number of file is $filenum"
}

directory                  #在脚本中调用函数

2、向函数传递参数

      shell中,向函数传递的参数仍然是以位置参数的方式来传递的,而不能传递数组等其他形式变量(与c不同)。利用函数参数的传递实现两数的四则运算。

#用于实现两数加、减、乘和除四则运算
#!/bin/bash

count()
{
    if [ $# -ne 3 ]             #3个参数,一个运算符两个数值
    then 
        echo "The  number of arguments is not 3! "
    fi
    
    let "s = 0"
    case $2 in
    +)                          #加法
        let "s = $1 + $3"
        echo "$1 + $3 = $s";;
    -)                          #减法
        let "s = $1 - $3"
        echo "$1 - $3 = $s";;
    \*)                         #乘法
       let "s = $1 * $3"
       echo "$1 * $3 = $s";;
     \/)                        #除法-取余,浮点数运算使用bc
        let "s = $1 / $3"
        echo "$1 / $3 = $s";;
    *)                          #其他
        echo "What you input is wrong!";;
    esac
}

echo "Please type your word: ( e.g. 1 + 1 )"
read a b c 
count $a $b $c

3、函数返回值

      有时需要函数执行完成后返回特定的值来完成脚本的后续操作。函数通过return返回退出状态,0表示true无错误,非0表示false有错误(与C不同)。

#根据用户输入显示星期
#!/bin/bash

show_week()
{
     echo -n "What you input is: "
     echo "$1"

    case $1 in 
    0)
        echo "Today is Sunday. "
        return 0;;
    1)
        echo "Today is Monday. "
        return 0;;
    2)
        echo "Today is Tuesday. "
        return 0;;
    3)
        echo "Today is Wednesday. "
        return 0;;
    4)
        echo "Today is Thursday. "
        return 0;;
    5)
        echo "Today is Friday. "
        return 0;;
    6)
        echo "Today is Saturday. "
        return 0;;
    *)
        return 1;;
    esac
}

#if show_week "$1"          #返回0表示函数输入的命令行参数是正确的
#也可以通过$?来获取函数执行的返回值
show_week "$1"
if [ $? -eq 0 ]
then
    echo "What you input is right! "
else 
    echo "What you input is wrong! "
fi
exit 0

4、函数调用

shell脚本中可以同时放置多个函数,函数之间允许相互调用,而且允许一个函数调用多个函数。

#用于显示一个不多于5位的正整数的位数,并按顺序显示各个数位的值
#!/bin/bash

count_of_int()
{
    if [ $1 -gt 9999 ]
    then
        let "place=5"         #5位数
    elif [ $1 -gt 999 ]
    then
        let "place=4"
    elif [ $1 -gt 99 ]
    then
        let "place=3"
    elif [ $1 -gt 9 ]
    then
       let "place=2"
    else
        let "place=1"         #1位数
    fi
    
    echo "The place of the $1 is $place."      #整数的位数
} 

num_of_int()
{
    let "ten_thousand = $1/10000"           #整数的数位分解值    
    let "thousand =$1/1000%10"
    let "hundred = $1/100%10"
    let "ten = $1%100/10"
    let "indiv = $1%10"

    if [ $ten_thousand -ne 0 ]
    then
       echo "$ten_thousand  $thousand  $hundred  $ten  $indiv"
    elif [ $thousand -ne 0 ]
    then
        echo "$thousand  $hundred  $ten  $indiv"
    elif [ $hundred -ne 0 ]
    then
        echo "$hundred  $ten  $indiv"
    elif [ $ten -ne 0 ]
    then
       echo "$ten  $indiv"
    else
       echo "$indiv"
    fi
}

show()
{
    echo "Please input the number(1-99999): "
    read num
   
    count_of_int $num
    num_of_int $num
}

show

执行脚本,输入整数2014,该数是四位数,千位是2,百位是0,十位是1,个位是4。

5、函数中局部和全局变量

      shell中,可以通过local关键字来申明局部变量,局部变量将局限在函数范围内。函数可调用函数外的全局变量,若一个局部变量和一个全局变量的名字相同,则在函数中局部变量会覆盖掉全局变量。

#!/bin/bash

text="global variable"

use_local_var_fun()
{
    local text="local variable"          #local声明为局部变量,否则会修改全局text的值
    echo "in function------"$text        #暂时覆盖掉全局变量的值
}

use_local_var_fun

echo "Out of function------"$text        #text的值为开始定义的值
exit 0

6、函数递归

(1)shell中执行递归函数可以直接或间接地反复调用其自身,每调用一层就进入新的一层,主调函数又是被调函数。

(2)使用局部变量进行递归实现阶乘运算,也可采用递推法实现。

#阶乘运算,当n=0时 0!=1,当n>=1时n!=n*(n-1)!
#!/bin/bash

fact ()
{
    local num=$1         #函数需将先前的局部值进行逐个还原,故设置成局部的变量
    echo $num
    
    if [ "$num" -eq 0 ]
    then
        factorial=1
    else
        let "decnum=num-1"

        fact $decnum

        let "factorial=$num * $?"
    fi
    return $factorial
}

fact $1
echo "Factorial of $1 is $?"

exit 0
(3)递归实现汉诺塔的问题(不使用局部变量的递归)

#汉诺塔算法
#!/bin/bash

move=0

dohanoi() 
{
    if [ $1 -eq 0 ]
    then
       echo "" 
    else
        dohanoi "$(($1-1))" $2 $4 $3
        echo "move $2 ----> $3"
        
        let "move=move+1"

        dohanoi "$(($1-1))" $4 $3 $2
    fi
    
    if [ $# -eq 1 ]
    then
        if [ "$(( $1 > 1 ))" -eq 1 ]
        then
            dohanoi $1 A C B
            echo "Total moves  = $move"
        else
           echo "The number of disk which you input is illegal! "
         fi
    fi
}

echo "Please input the num of disk:"
read num
dohanoi $num 'A' 'B' 'C'

三、总结

(1)函数间的相会调用增加了shell编程的灵活性和代码的可重用性,对脚本语言来说很是实用。

(2)函数的递归调用应进一步理解,阶乘和汉诺塔的实现可逐步分析

(3)通过函数可以封装自己的函数库,减少以后开发的难度并使用代码的可重复性

你可能感兴趣的:(Shell基础)