[2-02-02].第59节:功能函数 - 函数基础

发布于:2025-06-21 ⋅ 阅读:(18) ⋅ 点赞:(0)

服务器端操作学习大纲


一、函数基础

需求场景

  • 在shell脚本的编写过程中,我们经常会遇到一些功能代码场景:多条命令组合在一起,实现一个特定的功能场景逻辑、一些命令在脚本内部的多个位置频繁出现。在这些场景的代码量往往不多,但是频繁使用的话,会导致脚本的整体逻辑脉络比较松散和框架散乱,所以我们需要一种脚本逻辑,不仅仅能够满足松散代码的功能目的,还能精简重复的代码。函数就是来满足这种场景的解决方案 – 而函数,也是所谓的面向对象编程的一种表现样式

什么是函数:

  • 所谓的函数,本质上就是一段能够满足特定功能的代码块。一旦定义好函数代码后,我们就可以在脚本的很多位置随意的使用。
    定义功能代码块的动作叫函数定义,使用函数代码的动作叫函数调用

函数的优势:

  • 代码模块化,调用方便,节省内存
  • 代码模块化,代码量少,排错简单
  • 代码模块化,可以改变代码的执行顺序

二、定义简单函数:

2.1.基本语法

  • 样式1:定义函数:
    function 函数名{		
        函数体				
    }	
  • 样式2:简约格式
函数名() {		
	函数体				
}

2.2.注意事项:

  • function 的作用和 () 的作用是一样的,都是定义一个函数
  • 函数的名称是自定义的,而且在脚本范围内必须唯一
  • 函数体内是普通的能够正常执行的命令,命令的执行流程符合顺序逻辑

2.3.函数调用:

  • 函数名
  • 注意:
    • 函数名出现在任何位置,就代表在该位置调用函数内代码块的执行
    • 函数名一般在函数定义后调用,否则的话会发生报错

2.4.简单实践:

实践1-标准函数的实践

  • 1.简单函数的定义与调用:
[root@localhost ~]# cat function_simple_test.sh
#!/bin/bash
# 定制一个函数,提示脚本的使用方式
function Usage {
    echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}

# 定制脚本使用逻辑
if [ $# -eq 1 ]
then
    echo "您输入的脚本参数是1个"
else
    Usage
fi
脚本执行效果
[root@localhost ~]# /bin/bash function_simple_test.sh
脚本的使用帮助信息: xxx
[root@localhost ~]# /bin/bash function_simple_test.sh aa
您输入的脚本参数是1个
[root@localhost ~]# /bin/bash function_simple_test.sh aa bb
脚本的使用帮助信息: xxx

实践2-变种函数的实践

[root@localhost ~]# cat function_simple_test2.sh
#!/bin/bash
# 功能:简单函数的定义和调用

# 定制一个函数,提示脚本的使用方式
Usage() {
    echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}

# 定制脚本使用逻辑
if [ $# -eq 1 ]
then
    echo "您输入的脚本参数是1个"
else
    Usage
fi
脚本执行效果
[root@localhost ~]# /bin/bash function_simple_test2.sh
脚本的使用帮助信息: xxx
[root@localhost ~]# /bin/bash function_simple_test2.sh aa
您输入的脚本参数是1个
[root@localhost ~]# /bin/bash function_simple_test2.sh aa bb
脚本的使用帮助信息: xxx

实践3-函数的调用顺序和名称唯一实践

  • 功能:简单函数的定义和调用
[root@localhost ~]# cat function_simple_test3.sh
#!/bin/bash

# 定制一个函数,提示脚本的使用方式
Usage() {
    echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}
echo "第一次调用效果: "
Usage

# 定制同名的函数,提示脚本的使用方式
Usage() {
    echo -e "\e[31m脚本的使用帮助信息-------: xxx\e[0m"
}


# 定制脚本使用逻辑
if [ $# -eq 1 ]
then
    # 调用一个后面才会生成的函数
    func
else
    Usage
fi

# 定制一个函数
func() {
    echo "您输入的脚本参数是1个"
}

  • 2.结果:
[root@localhost ~]# /bin/bash function_simple_test3.sh
第一次调用效果:
脚本的使用帮助信息: xxx
脚本的使用帮助信息-------: xxx
[root@localhost ~]# /bin/bash function_simple_test3.sh a
第一次调用效果:
脚本的使用帮助信息: xxx
function_simple_test3.sh:行18: func: 未找到命令
  • 3.总结:
    • 函数名称重复的话,会导致同名函数被覆盖
    • 函数在没有定义前调用的话,会导致异常报错

三、定义传参函数

3.1.简介

  • 简单的函数定义和调用的实践,我们只能实现固定内容的输出,不具有灵活性。其实函数作为shell脚本内部的小脚本也支持脚本传参的一系列能力

3.2.定义传参函数:

a.语法:

函数名() {		
        函数体	${变量名}			
    }

b.注意:

  • 注意:函数体内通过 ${变量名} 来实现函数体的功能通用性

3.3.调用传参函数:

a.语法:

	函数名 参数			

b.注意:

  • 函数在调用的时候,接收一些参数并传输到函数体内部

3.4.案例:

实践1-传参函数实践

  • 传参函数定义和调用
[root@localhost ~]# cat function_arg_input.sh
#!/bin/bash
# 功能:传参函数定义和调用

# 定制数据运算的函数
add_func() {
    echo $(( $1 + $2 ))
}
sub_func() {
    echo $(( $1 - $2 ))
}
mul_func() {
    echo $(( $1 * $2 ))
}
div_func() {
    echo $(( $1 / $2 ))
}

echo -n "4+3="; add_func 4 3
echo -n "4-3="; sub_func 4 3
echo -n "4*3="; mul_func 4 3
echo -n "4/3="; div_func 4 3
  • 2.脚本执行效果
[root@localhost ~]# /bin/bash function_arg_input.sh
4+3=7
4-3=1
4*3=12
4/3=1

3.5.脚本传参

a.简介

  • 传参函数定义和调用的实践,实现了函数层面的灵活性,但是它受到函数调用本身的参数限制。往往这些参数我们需要在脚本执行的时候传递进去,从而实现脚本功能的灵活性。

b.基本语法

  • 定义函数:
    函数名() {		
        函数体	${函数参数}			
    }
  • 调用函数:函数名 ${脚本参数}
  • 脚本执行:/bin/bash /path/to/scripts.sh arg

c.注意:

  • 由于脚本内部调用脚本参数和函数体内调用函数参数都遵循位置变量的使用,所以,一般情况下,我们会借助于临时变量的方式接收各自的参数,从而避免引起误会

d.实践1-脚本传参函数实践

查看脚本内容
[root@localhost ~]# cat function_arg_scripts.sh
#!/bin/bash
# 功能:脚本传参函数调用

# 定制数据运算的函数
add_func() {
    echo $(( $1 + $2 ))
}
sub_func() {
    echo $(( $1 - $2 ))
}
mul_func() {
    echo $(( $1 * $2 ))
}
div_func() {
    echo $(( $1 / $2 ))
}

[ $# -ne 2  ] && echo "必须传递两个数字参数" && exit
echo -n "$1+$2="; add_func $1 $2
echo -n "$1-$2="; sub_func $1 $2
echo -n "$1*$2="; mul_func $1 $2
echo -n "$1/$2="; div_func $1 $2

注意:
	这种简单的脚本传参函数调用,导致大量的位置参数,容易引起混乱,需要改造
  • 2.脚本执行效果
[root@localhost ~]# /bin/bash function_arg_scripts.sh
必须传递两个数字参数
[root@localhost ~]# /bin/bash function_arg_scripts.sh 5 4
5+4=9
5-4=1
5*4=20
5/4=1

e.实践2-实践2-脚本传参函数进阶实践

查看脚本内容
[root@localhost ~]# cat function_arg_scripts2.sh
#!/bin/bash
# 功能:传参函数定义和调用

# 接收脚本传参
arg1=$1
arg2=$2
# 定制数据运算的函数
add_func() {
    num1=$1
    num2=$2
    echo $(( ${num1} + ${num2} ))
}
sub_func() {
    num1=$1
    num2=$2
    echo $(( ${num1} - ${num2} ))
}
mul_func() {
    num1=$1
    num2=$2
    echo $(( ${num1} * ${num2} ))
}
div_func() {
    num1=$1
    num2=$2
    echo $(( ${num1} / ${num2} ))
}

[ $# -ne 2  ] && echo "必须传递两个数字参数" && exit
echo -n "${arg1}+${arg2}="; add_func ${arg1} ${arg2}
echo -n "${arg1}-${arg2}="; sub_func ${arg1} ${arg2}
echo -n "${arg1}*${arg2}="; mul_func ${arg1} ${arg2}
echo -n "${arg1}/${arg2}="; div_func ${arg1} ${arg2}
脚本执行效果
[root@localhost ~]# /bin/bash function_arg_scripts2.sh
必须传递两个数字参数
[root@localhost ~]# /bin/bash function_arg_scripts2.sh 7 5
7+5=12
7-5=2
7*5=35
7/5=1

四、函数退出

4.1.简介

  • 我们可以将函数代码块,看成shell脚本内部的小型脚本,所以说函数代码块也会有执行状态返回值。对于函数来说,它通常支持两种种状态返回值的样式
  • 样式1-默认的退出状态:
    • 默认情况下,函数的退出状态是函数体内的最后一条命令的退出状态,可以通过 $? 来获取
  • 样式2-return定制状态返回值:
    • 在函数体内部,通过return定制状态返回值的内容

4.2.注意:

  • return的状态返回值必须尽快使用,否则会被其他return的值覆盖
  • return的状态返回值必须在 0-255,否则失效

4.3.简单实践:

实践1-默认退出状态

[root@localhost ~]# cat function_exit_status1.sh
#!/bin/bash
# 功能:函数默认状态返回值

# 定制成功运行的函数
ok_func() {
    echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}
# 定制一个运行失败的函数
err_func() {
    666666
}
# 定制脚本使用逻辑
if [ $# -eq 1 ]
then
    err_func
    echo "错误函数的执行状态返回值: " $?
else
    ok_func
    echo "成功函数的执行状态返回值: " $?
fi
脚本执行效果
[root@localhost ~]# /bin/bash function_exit_status1.sh
脚本的使用帮助信息: xxx
成功函数的执行状态返回值:  0
[root@localhost ~]# /bin/bash function_exit_status1.sh aa
function_exit_status1.sh:行10: 666666: 未找到命令
错误函数的执行状态返回值:  127
[root@localhost ~]# lll; echo $?
bash: lll: 未找到命令
127
结果显示:
	对于异常的函数来说,默认的状态返回值有安全隐患

实践2-return定制函数的返回值实践

[root@localhost ~]# cat function_exit_status2.sh
#!/bin/bash
# 功能:return定制函数状态返回值

# 定制成功运行的函数
ok_func() {
    echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
    # 定制超范围的状态返回值
    return 666
}
# 定制一个运行失败的函数
err_func() {
    666666
    # 定制状态返回值
    return 222
}
# 定制脚本使用逻辑
if [ $# -eq 1 ]
then
    err_func
    echo "错误函数的执行状态返回值: " $?
else
    ok_func
    echo "成功函数的执行状态返回值: " $?
fi
脚本执行效果
[root@localhost ~]# /bin/bash function_exit_status2.sh
脚本的使用帮助信息: xxx
成功函数的执行状态返回值:  154
[root@localhost ~]# /bin/bash function_exit_status2.sh aa
function_exit_status2.sh:行12: 666666: 未找到命令
错误函数的执行状态返回值:  222
结果显示:
	return的状态返回值范围必须满足要求

五、综合案例

5.1.信息采集

  • 脚本实践-采集系统负载信息
[root@localhost ~]# cat function_systemctl_load.sh
#!/bin/bash
# 功能:采集系统负载信息
# 版本:v0.3

# 定制资源类型
resource_type=(CPU MEM)


# 定制cpu信息输出函数
cpu_info() {
	cpu_attribute=(1 5 15)
	cpu_load=($(uptime | tr -s " " | cut -d " " -f 11-13 | tr "," " "))
    echo -e "\e[31m\t系统CPU负载信息\e[0m"
    echo -e "\e[32m================================"
    for index in ${!cpu_attribute[@]}
    do
        echo "CPU ${cpu_attribute[$index]} min平均负载为: ${cpu_load[$index]}" 
    done
    echo -e "================================\e[0m"	
}
# 获取内存相关属性信息
mem_info() {
	free_attribute=(总量 使用 空闲)
	free_info=($(free -m | grep Mem | tr -s " " | cut -d " " -f 2-4))
    echo -e "\e[31m\t系统内存负载信息\e[0m"
    echo -e "\e[32m================================"
    for index in ${!free_attribute[@]}
    do
        echo "内存 ${free_attribute[$index]} 信息为: ${free_info[$index]} M" 
    done
    echo -e "================================\e[0m"
}

# 服务的操作提示
echo -e "\e[31m---------------查看资源操作动作---------------
 1: CPU  2: MEM
-------------------------------------------"'\033[0m'
# 选择服务操作类型
while true
do
    read -p "> 请输入要查看的资源信息类型: " resource_id
    echo
    case ${resource_type[$resource_id-1]} in
       "CPU")
            cpu_info;;
        "MEM")
            mem_info;;
        *)
            echo -e "\e[31m\t请输入有效的信息类型\e[0m";;
    esac
done
  • 2.测试:
脚本使用效果
[root@localhost ~]# /bin/bash function_systemctl_load.sh
---------------查看资源操作动作---------------
 1: CPU  2: MEM
-------------------------------------------
> 请输入要查看的资源信息类型: 1

        系统CPU负载信息
================================
CPU 1 min平均负载为: 0.00
CPU 5 min平均负载为: 0.01
CPU 15 min平均负载为: 0.05
================================
> 请输入要查看的资源信息类型: 2

        系统内存负载信息
================================
内存 总量 信息为: 3770 M
内存 使用 信息为: 237 M
内存 空闲 信息为: 3290 M
================================
> 请输入要查看的资源信息类型: 3

        请输入有效的信息类型
> 请输入要查看的资源信息类型: ^C
[root@localhost ~]#

5.2.环境部署

a.需求

  • 定制kubernetes环境部署管理的功能脚本改造
    • 功能函数实现
    • 扩充while循环执行功能
    • 增加q退出环境功能

b.脚本内容

  • 查看脚本内容
[root@localhost ~]# cat function_kubernetes_manager.sh
#!/bin/bash
# 功能:定制kubernetes环境部署管理的功能
# 版本:v0.2


# 定制数组变量
env_array=(base ha k8s_base master slave)

# 监控平台的信息提示
menu(){
    echo -e "\e[31m     欢迎使用kubernetes部署平台"
    echo -e "\e[32m-----------请选择部署阶段-----------"
    echo -e " 1: 基础环境部署"
    echo -e " 2: 高可用环境部署"
    echo -e " 3: kubernetes基础环境部署"
    echo -e " 4: 主角色环境部署"
    echo -e " 5: 从角色环境部署"
    echo -e " q: 退出"
    echo -e "----------------------------------\033[0m"
}
# 定制基础环境
os_base_func(){
    echo -e "\e[31m开始基础环境部署..."
    echo "1 执行跨主机免密码操作"
    echo "2 执行时间同步操作"
    echo "3 执行内核配置操作"
    echo -e "4 执行容器私有仓库部署操作\e[0m"
}

# 定制高可用环境
ha_func(){
    echo -e "\e[31高可用环境部署..."
    echo "1 执行高可用环境部署操作"
    echo -e "2 执行负载均衡环境部署操作\e[0m"
}

# 定制k8s基础环境
k8s_base_func(){
    echo -e "\e[31mkubernetes基础环境部署..."
    echo "1 执行证书管理操作"
    echo "2 执行etcd环境部署操作"
    echo -e "3 执行集群证书配置操作\e[0m"
}

# 定制主角色环境
master_func(){
    echo -e "\e[31m主角色环境部署..."
    echo "1 执行apiserver环境部署操作"
    echo "2 执行scheduler环境部署操作"
    echo "3 执行controller环境部署操作"
    echo "4 执行认证配置操作"
    echo "5 执行容器环境部署操作"
    echo "6 执行kubelet环境部署操作"
    echo -e "7 执行kube-proxy环境部署\e[0m"
}
# 定制从角色环境
slave_func(){
    echo -e "\e[31m主角色环境部署..."
    echo "1 执行容器环境部署操作"
    echo "2 执行kubelet环境部署操作"
    echo -e "3 执行kube-proxy环境部署\e[0m"
}
# 定制错误提示信息
usage_func(){
    echo -e "\e[31m请输入有效的功能场景标识\e[0m"
}


# 脚本内容的判断
while true
do
    # 定制业务逻辑
    menu
    read -p "请输入功能标识: " env_id
    if [ ${env_id} == "q" ];then
        exit
    else
        # 执行配套业务逻辑
        case "${env_array[$env_id-1]}" in
            "base")
                os_base_func;;
            "ha")
                ha_func;;
            "k8s_base")
                k8s_base_func;;
            "master")
                master_func;;
            "slave")
                slave_func;;
            *)
                usage_func;;
        esac
    fi
done
  • 2.测试:
[root@localhost ~]# /bin/bash function_kubernetes_manager.sh
     欢迎使用kubernetes部署平台
-----------请选择部署阶段-----------
 1: 基础环境部署
 2: 高可用环境部署
 3: kubernetes基础环境部署
 4: 主角色环境部署
 5: 从角色环境部署
 q: 退出
----------------------------------
请输入功能标识: 6
请输入有效的功能场景标识
     欢迎使用kubernetes部署平台
-----------请选择部署阶段-----------
 1: 基础环境部署
 2: 高可用环境部署
 3: kubernetes基础环境部署
 4: 主角色环境部署
 5: 从角色环境部署
 q: 退出
----------------------------------
请输入功能标识: 5
主角色环境部署...
1 执行容器环境部署操作
2 执行kubelet环境部署操作
3 执行kube-proxy环境部署
     欢迎使用kubernetes部署平台
-----------请选择部署阶段-----------
 1: 基础环境部署
 2: 高可用环境部署
 3: kubernetes基础环境部署
 4: 主角色环境部署
 5: 从角色环境部署
 q: 退出
----------------------------------
请输入功能标识: q


网站公告

今日签到

点亮在社区的每一天
去签到