一、Shell函数

1)Shell函数的概述

Shell函数的优点

  • 避免代码重复
  • 将大的工程分割为若干小的功能模块,代码的可读性更强

Shell函数的定义

#函数定义1
function 函数名 {
  命令序列
}

#函数定义2
函数名() {
  命令序列
}

##### main #######
#可以在主代码区域中直接使用函数名调用函数
函数名

Shell函数的返回值

return表示退出函数并返回一个退出值,脚本中可以用$?显示该值

使用原则

1.函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码

2.退出状态码必须是0~255,超过时值将为除以256取余

示例1:
在函数内用return退出函数并返回函数的值,在函数外用echo $?获取返回值
注:返回值的范围只能在0~255,超过部分需除以256取余

function db1 {
  read -p "请输入:" value
  return $[$value * 2]
}

##### main #######
db1
echo $?

return的返回值的范围是0-255,超过部分除以256取余,得不到我们想要的结果,所以我们使用echo

示例2:
子啊函数内用echo输出值,在函数体外可用 变量=$(函数名) 获取函数的返回值

db1() {
  read -p "请输入:" value
  echo $[$value * 2]
}

##### main #######
result=`db1`
echo $result

函数传参

sum1() {
  sum=$[$1 + $2]
  echo $sum
}

##### main #######
read -p "输入第一个参数:" first
read -p "输入第二个参数:" second
sum1 $first $second

示例

#!/bin/bash

#定义函数
sum() {
  #函数体内部的$1 $2 代表的是调用函数时,函数后面跟的位置参数
  sum=$[$1 - $2]
  echo $sum
  echo "在函数体内部的\$#代表调用函数时,函数后面跟的参数个数,当前函数后面有$#个参数"
  echo "在函数体内部的\$@代表调用函数时,函数后面跟的所有参数,当前函数后面的参数有:$@"
  echo "在函数体内部,\$0代表$0"
}


##### main #######
echo "在函数体外时,\$#代表脚本后面跟的参数个数,当前脚本后面有$#个参数"
echo "在函数体外时,\$@代表脚本后面跟的所有参数,当前脚本后面参数有:$@"
echo "在函数体外,\$0代表$0"

#调用函数
#函数体外的$1 $2 代表的是执行脚本时,脚本后面跟的位置参数
sum $2 $1

Shell函数变量的作用范围

函数默认只能在脚本内的shell环境有效(使用source执行脚本,也会影响系统的当前shell环境)

脚本中的变量默认全局有效(即函数体内外部有效)

在函数体内执行 local 变量,可将变量限定在函数体内部使用

#!/bin/bash
i=8
i=9
echo $i
#输出9,因为i的值被覆盖了
#!/bin/bash
 
myfun() {
    i=9
}
########## main ###########
myfun
i=8
echo $i
#输出8
#主函数开始运行,第一步函数调用i=9,然后i=8覆盖后输出
#!/bin/bash
 
myfun() {
    i=9
    echo $i
}
########## main ###########
myfun
i=8
echo $i
#输出9 8
#调用函数时输出函数里面i=9,而后输出的i被i=8覆盖
#!/bin/bash
myfun() {
    local i
    #local定义的变量只能在local之后到函数结束前有效
    i=9
    echo $i
}
########## main ###########
i=8
myfun
echo $i
#输出9  8,而不是9 9
#local限定了函数i的值,函数外不能重新覆盖,而没有local的变量时全局有效的

2)递归函数

函数调用自己本身的函数

示例1:阶乘

#!/bin/bash
#使用递归计算阶乘
 
fact() {
        if [ $1 -eq 1 ]
        #$1,表示函数后面调用的变量,如果调用的值是1,输出值就是1
        then
                echo 1
        else
                local temp=$[$1-1]
                #定义一个变量temp为传入函数的参数减1,并且为局部变量
                local result=$(fact $temp)
                #每次调用函数自己,每次temp减1,直到为1
                echo $[$1 * $result]
        fi
}

##### main #####
read -p "请输入一个正整数:" num
result=$(fact $num)
#跟上面的result不影响,上面的result是局部变量,仅在函数内有效
echo "$num 的阶乘为: $result"


########实现过程

fact 5

$1=5   temp=4   result=$(fact 4)   echo 5 * $(fact 4)
$1=4   temp=3   result=$(fact 3)   echo 5 * 4*$(fact 3)
$1=3   temp=2   result=$(fact 2)   echo 5 * 4 * 3*$(fact 2)
$1=2   temp=1   result=$(fact 1)   echo 5 * 4 * 3 * 2*$(fact 1)
$1=1                                                2*1

示例2:递归目录

mkdir -p /root/bin/aa/bb/cc/dd
touch /root/bin/aa/bb/cc/dd/abc.txt

#!/bin/bash
#递归/root/bin目录,显示他的所有子目录和文件
list() {
        for fd in $1/*
#逐个检查$1参数指定目录下的所有文件或子目录
        do
                if [ -d $fd ]
#判断如果是目录就输出,并且通过递归把这个目录下的所有文件或子目录再逐个检查,如果发现还有子目录会按照这个方式一直检查下去
                then
                        echo "$fd 是目录"
                        list "$fd"
                        #递归函数调用
                else
                        echo "$fd 是文件"
                fi
        done
}

##### main #####
list "/root/bin"

3)函数库

可以事先创建一个函数库,在里面定义各种常用的函数然后可以在别的shell脚本中直接引用

#函数库
jiafa() {
        echo $[$1 + $2]
}
jianfa() {
        echo $[$1 - $2]
}
chengfa() {
        echo $[$1 * $2]
}
chufa() {
        if [ $2 -eq 0 ]
        then
                echo "除数不能为0"
        else
                echo $[$1 / $2]
        fi
}
fact() {
        if [ $1 -eq 1 ]
        then
                echo 1
        else
                local temp=$[$1-1]
                local result=$(fact $temp)
                echo $[$1 * $result]
        fi
}
#!/bin/bash

#加载函数库文件到当前脚本的shell
. /root/funcs

value1=10
value2=5

res1=$(jiafa ¥value1 $value2)
res2=$(jianfa ¥value1 $value2)
res3=$(chengfa ¥value1 $value2)
res4=$(chufa ¥value1 $value2)
res5=$(fact ¥value1 $value2)

echo "加法的结果为$res1"
echo "减法的结果为$res2"
echo "乘法的结果为$res3"
echo "除法的结果为$res4"
echo "阶乘的结果为$res5"
05-08 18:47