shell编程之函数以及函数中的递归

目录

前言

一、什么是函数

二、获取函数的返回值

示例1:return

示例2:echo

三、函数传参

四、函数变量的作用范围

五、递归

示例1:求阶乘

示例2:递归目录

六、函数库

七、总结


前言

初学者写的脚本

#/bin/bash
#准备工作
mount /dev/cdrom /mnt
cd /etc/yum.repos.d
mkdir repo.bak
mv *.repo repo.bak

#创建本地yum源仓库配置文件
echo '[local]' >> local.repo
echo 'name=local' >> local.repo
echo 'baseurl=file:///mnt' >> local.repo
echo 'enabled=1' >> local.repo
echo 'gpgcheck=0' >> local.repo
yum clean all && yum makecache

#安装httpd服务,并启动,设置开机自启动
yum install -y httpd
systemctl start httpd
systemctl enable httpd

这个脚本乍一看,没有什么问题,能够正常执行,但是流水账似的脚本,公司同事一看你就是个新手

老员工看一个人的脚本写的多不多,规不规范:

1.看你写的格式

2.有没有大量使用函数

老手修改后的脚本:

#/bin/bash
#准备工作
read_work () {
mount /dev/cdrom /mnt
cd /etc/yum.repos.d
mkdir repo.bak
mv *.repo repo.bak  
}
#创建本地yum源仓库配置文件
create_repo () {
echo '[local]' >> local.repo
echo 'name=local' >> local.repo
echo 'baseurl=file:///mnt' >> local.repo
echo 'enabled=1' >> local.repo
echo 'gpgcheck=0' >> local.repo
yum clean all && yum makecache  
}
#安装httpd服务,并启动,设置开机自启动
install_soft () {
yum install -y httpd
systemctl start httpd
systemctl enable httpd
}
##### main #######
read_work
create_repo
install_soft

这就是学函数的意义,使得外人读起来很方便理解你的代码逻辑 

一、什么是函数

  1. 使用函数可以避免代码重复
  2. 使用函数可以将大的工程分割为若干小的功能模块,代码的可读性更强
  3. 类似于Java的方法

#函数定义1
function 函数名 {
    
}
#函数定义2
函数名() {
    
}


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

法一:function 函数名 {    三部分之间都要有空格

法二:函数名() {    函数名和括号之间空格可有可无

二、获取函数的返回值

return表示退出函数并返回一个退出值,脚本中可以用$?变量结合echo输出该值

在函数体中用echo输出,并在函数体外可以使用变量赋值后可进一步对返回值操作

使用原则:

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

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

$?作用一:显示上一条命令是否正确

$?作用二:显示退出函数并返回的退出值

示例1:return

#!/bin/bash
#在文件上方先定义函数,然后在主代码部分调用函数
function test1 {
#function test1 { 之间都要有空格,否则执行不成功
        read -p "请输入一个整数:" num
        return $num
}
########## main ###########
#可以在主代码区域中直接使用函数名调用函数
test1
#调用函数
echo $?
#输出返回值

示例2:echo

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

#!/bin/bash
#在文件上方先定义函数,然后在主代码部分调用函数
function test1 {
#function test1 { 之间都要有空格,否则执行不成功
        read -p "请输入一个整数:" num
        return $[num * 2]
}
########## main ###########
#可以在主代码区域中直接使用函数名调用函数
test1
echo $?
#输出返回值

 

#!/bin/bash
#在文件上方先定义函数,然后在主代码部分调用函数
function test1 {
#function test1 { 之间都要有空格,否则执行不成功
        read -p "请输入一个整数:" num
        echo $[num * 2]
#改为echo直接在函数中输出
}
########## main ###########
#可以在主代码区域中直接使用函数名调用函数
test1

这个要自己多操作,光看写的东西不能够很好的领悟到其中的含义 

 三、函数传参

sum1() {
    sum=$[$1 + $2]
    echo $sum
}
########## main ###########
read -p "请输入第一个参数:" first
read -p "请输入第二个参数:" second
sum1 $first $second 

 

 

 

 

四、函数变量的作用范围

  1. 函数在shell脚本中仅在当前shell脚本环境中有效(用source执行脚本,在当前系统shell环境运行)
  2. shell脚本中变量默认全局有效
  3. 将变量限定在函数内部使用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
#输出98
#调用函数时输出函数里面i=9,而后输出的i被i=8覆盖
#!/bin/bash
myfun() {
    local i
    #local定义的变量只能在local之后到函数结束前有效
    i=9
    echo $i
}
########## main ###########
i=8
myfun
echo $i
#输出98,而不是99
#local限定了函数i的值,函数外不能重新覆盖,而没有local的变量时全局有效的

五、递归

简单来讲递归就是不停地调用本身,比较有名的递归算法有斐波拉契数列、汉诺塔等,有兴趣的小伙伴可以自行查阅资料了解一下

示例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]
                #用c语言理解就是这样一个过程: num*fact(num-1)
        fi
}
##### main #####
read -p "请输入一个正整数:" num
result=$(fact $num)
#跟上面的result不影响,上面的result是局部变量,仅在函数内有效
echo "$num 的阶乘为: $result"

实现过程

fact 5

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

 

示例2:递归目录

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

递归/root/bin目录,显示他的所有子目录和文件

#!/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"

 

 

 

 六、函数库

可以事先创建一个函数库,在里面定义各种常用的函数然后可以在别的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
}

 

 

 一定要在脚本中加载函数库,用source或者点(.)

七、总结

定义函数法一:

function 函数名

命令序列

}

定义函数法二:

函数名(){

命令序列

}


注意:

  1. 同名函数 后一个生效

  2. 调用函数一定要先定义

猜你喜欢

转载自blog.csdn.net/qq_42327944/article/details/124207459
今日推荐