Shell编程之函数与数组

目录

一 shell函数

1 函数的用法

(1)两个数求和

(2)系统资源监控并报警函数

2 函数标量的作用范围

3 函数的参数

4 递归函数

二 shell数组

1 获取数组长度

2 读取某下标赋值

3 数组遍历

4 数组切片

5 数组替换

6 数组删除

三 shell脚本调试

四 总结


一 shell函数

1 函数的用法

Shell 函数是:

  • 命名的命令集合:给一组命令赋予一个名称,便于重复调用

  • 脚本中的子程序:类似于其他编程语言中的函数或方法

  • 参数化执行单元:可以接收参数并返回结果

  • 代码复用机制:避免重复编写相同代码

Shell 函数语法是:

#!/bin/bash

#

sum() {             #在大括号里写函数体

            命令序列

[ return  x ]

}

#调用函数sum

sum

参数说明
sum函数名
{表示函数执行命令的入口,该符号可以与函数名同行也可以在函数名下一行的句首
}表示函数体结束,两个大括号之间 { } 是函数体
命令序列部分可以是任意的shell命令,也可以调用其他函数
return表示退出函数返回一个退出值,通过返回值判断执行是否成功,也可以用exit终止整个shell脚本

(1)两个数求和

应用示例:

#!/bin/bash
#
sum() {
echo "请输入第一个数字:"
read num1
if ! [[ $num1 =~ ^[0-9]+$ ]]; then         # ! 用于取反,判断num1是否为整数。+ 任意一个或多个数字^开头,$结尾。
      echo "你输入的第一个数不是整数,请重新运行脚本"
      return 1
fi

echo "请输入第二个数字:"
read num2
if ! [[ $num2 =~ ^[0-9]+$ ]]; then         # ! 用于取反,判断num1是否为整数。+ 任意一个或多个数字^开头,$结尾。
      echo "你输入的第二个数不是整数,请重新运行脚本"
      return 1
fi

#计算2数之和
result=$((num1 + num2))           #也可以写成 $( expr num1 + num2  )

#输出结果
echo "2数之和为:$result"


}


#调用sum函数
sum

示例验证:

[root@Euler04 ~]# vim aaa.sh
[root@Euler04 ~]# chmod +x aaa.sh
[root@Euler04 ~]# bash aaa.sh
请输入第一个数字:
2
请输入第二个数字:
3
2数之和为:5
[root@Euler04 ~]# bash aaa.sh
请输入第一个数字:
a
你输入的第一个数不是整数,请重新运行脚本

(2)系统资源监控并报警函数

应用示例:

#!/bin/bash
#发送报警信息的函数
send_alert() {             #在大括号里写函数体
        local message=$1
        echo "ALERT: $message"
        #这里可以添加发送邮件,短信等报警逻辑
}


#系统资源监控函数
monitor_system_resources() {
        local cpu_threshold=$1
        local mem_threshold=$2
        local interval=$3

while true;do
        #获取CPU使用率
        cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $3}')
        #获取内存使用率
        mem_usage=$(free | awk '/Mem/ {printf("%.2f", $3/$2 * 100)}')

        if (( $(echo "$cpu_usage > $cpu_threshold" | bc -l) )); then
                send_alert "CPU usage ($cpu_usage%)."
        fi


        if (( $(echo "$mem_usage > $mem_threshold" | bc -l) )); then
                send_alert "Memory usage ($mem_usage%)."
        fi


        sleep "$interval"
done

方向关键点
参数设计定义监控阈值(CPU/内存/磁盘)、检查间隔、报警方式(日志/邮件/Webhook)
循环监控使用 while 循环定时检查资源,对比阈值判断是否触发报警
报警处理支持多种报警方式(日志、邮件、短信、Webhook),确保问题及时通知管理员

示例验证:

[root@Euler04 ~]# vim bb.sh
[root@Euler04 ~]# chmod +x bb.sh
[root@Euler04 ~]# bash bb.sh
ALERT: Memory usage (15.97%).
ALERT: Memory usage (16.04%).

2 函数标量的作用范围

概念总结:

  • 局部变量:函数内部使用 local 声明的变量,只在函数内有效

  • 全局变量:函数外部定义的变量,整个脚本可见

  • 环境变量:使用 export 导出的变量,子进程可见

  • 变量遮蔽:局部变量会遮蔽同名的全局变量

应用示例:

#!/bin/bash
#
myfun() {
        local i
        i=8
        echo $!

}
i=9
myfun
echo $i

示例验证:

[root@Euler04 ~]# vim bbb.sh
[root@Euler04 ~]# chmod +x bbb.sh
[root@Euler04 ~]# bash bbb.sh

9

3 函数的参数

概念总结

  • 位置参数$1$2, ..., $9 表示第1到第9个参数

  • 特殊参数

    • $0:脚本/函数名

    • $#:参数个数

    • $@:所有参数列表

    • $*:所有参数组合成一个字符串

  • 参数扩展${1:-默认值} 设置参数默认值

应用示例:

#!/bin/bash
#
mydir="/data" outfile="${mydir}/my.log"
[ -e "${mydir}" ] || mkdir -p ${mydir}

appendfile() {

        echo "$2" >> "$1"

}

appendfile ${outfile} "first line content"
appendfile ${outfile} "second line content"

示例验证:

[root@Euler04 ~]# vim cc.sh
[root@Euler04 ~]# chmod +x cc.sh
[root@Euler04 ~]# bash cc.sh

[root@Euler04 ~]# cat /data/my.log
first line content
second line content

4 递归函数

概念总结:

  • 递归函数:函数调用自身

  • 必要条件

    • 递归终止条件

    • 每次递归向终止条件推进

  • 注意事项

    • 确保有终止条件,避免无限递归

    • 递归深度过大可能导致栈溢出

    • 相比迭代效率较低

应用示例:

#!/bin/bash
#
#定义递归遍历目录的函数
traverse_directory() {
        local dir=$1
        #遍历当前目录下的所有文件和文件夹
        for itme in "$dir"/*; do
                if [ -d "$item" ]; then
                        #如果是目录,递归调用函数继续遍历
                        echo "Directory: $item"
                        traverse_directory "$item"
                elif [ -f "$item" ]; then
                        #如果是文件,输出文件路径
                        echo "File: $item"
                fi
        done

}

#调用函数,从当前目录开始遍历
traverse_directory "."

二 shell数组

概念:

Shell数组是一种可以存储多个值的变量,在Bash中主要分为两种类型:

  • 索引数组(Indexed Arrays):使用数字作为下标(从0开始)

  • 关联数组(Associative Arrays):使用字符串作为下标(需要Bash 4.0+)

数组常用定义方法包括以下几种:

方法一:

数组名=( value0  value1  value2  value3......)

方法二:

数组名=( [0]=value  [1]=value  [2]=value  [3]=value......)

方法三:

列表名=“value0  value1  value2  value3......”      数组名=($列表名)

方法四:

数组名[0]=“value”  数组名[1]=“value”  数组名[2]=“value”........

1 获取数组长度

数组的语法

$ { #数组名[ @ ] } 或 $ {#数组名[ * ] }

//@ ,*该数组所有的函数

例子:aaa=( 1 2 3 4 5 6 )

           for  i  in  ${ aaa[ @ ] }

           do

                        echo  $i

           Done

应用示例:

[root@Euler04 ~]# arr_number=(1 2 3 4 5)
[root@Euler04 ~]# arr_length=${#arr_number[*]}
[root@Euler04 ~]# echo $arr_length
5
[root@Euler04 ~]# arr_length_1=${#arr_number[@]}
[root@Euler04 ~]# echo $arr_length_1
5

2 读取某下标赋值

在Shell中读取数组特定下标的值并赋给变量的基本语法是:

variable_name=${array_name[index]}       变量名=${ 元素[ 序列 ] }

应用示例:

[root@Euler04 ~]# arr_index2=${arr_number[2]}
[root@Euler04 ~]# echo $arr_index2
3

3 数组遍历

概念:

数组遍历是指按照一定顺序访问数组中每个元素的过程。在Shell脚本中,遍历数组是处理数组数据的基本操作之一。

数组遍历常用语法:

for element in "${array[@]}"
do
    # 处理每个$element
done

特点:

  • ${array[@]}展开为所有数组元素

  • 引号保护元素中的空格不被分割

  • 保持元素原始值

应用示例:

#!/bin/bash
#
arr_number=(1 2 3 4 5)
for v in ${arr_number[@]}
do
        echo $v
done

示例验证:

[root@Euler04 ~]# vim dd.sh
[root@Euler04 ~]# chmod +x dd.sh
[root@Euler04 ~]# bash dd.sh
1
2
3

4 数组切片

概念:

数组切片是指从原数组中提取一个连续的子序列(子数组)。Shell通过特定的语法格式支持数组切片操作,可以方便地获取数组的一部分。

语法:

${array[@]:起始索引:长度}     或    ${array[*]:起始索引:长度}

参数:

  1. 起始索引

    • 从0开始计数

    • 可以是负数(Bash 4.2+),表示从数组末尾开始计算

    • 如果省略,默认为0

  2. 长度

    • 要提取的元素个数

    • 如果省略,提取从起始索引到数组末尾的所有元素

应用示例:

array=("a" "b" "c" "d" "e" "f")

# 从索引1开始取3个元素
echo "${array[@]:1:3}"  # 输出: b c d

# 从索引2开始到末尾
echo "${array[@]:2}"    # 输出: c d e f

5 数组替换

概念:

数组替换是指对数组中的元素进行内容替换操作,生成一个新数组而不改变原始数组。Shell提供了灵活的数组元素替换语法,支持简单的模式匹配和替换。

语法:

# 单个元素替换
${array[index]/模式/替换内容}

# 全局替换(所有元素)
${array[@]/模式/替换内容}

应用示例:

fruits=("apple" "banana" "appricot")

# 替换第一个匹配的字符
echo "${fruits[@]/a/A}"  # 输出: Apple bAnana Appricot

# 使用双斜杠//表示全局替换
echo "${fruits[@]//a/A}"  # 输出: Apple bAnAnA Appricot

# 使用/#匹配开头
echo "${fruits[@]/#a/A}"  # 输出: Apple banana appricot

6 数组删除

概念:

数组删除是指从数组中移除一个或多个元素的操作。在Shell中,数组删除主要分为两种形式:

  1. 删除单个元素 - 移除数组中指定位置的元素

  2. 删除整个数组 - 完全移除数组变量

语法:

unset array_name[index]     //删除单个元素

unset array_name          //删除整个数组

应用示例:

files=("a.txt" "b.jpg" "c.txt")

# 删除所有.txt文件
for i in "${!files[@]}"; do
    if [[ "${files[i]}" == *.txt ]]; then
        unset files[i]
    fi
done

Shell数组删除关键点:

  • 使用unset命令删除元素或整个数组

  • 删除元素后数组变为稀疏

  • 不会自动重新索引数组

  • 可以删除普通数组和关联数组的元素

  • 删除整个数组会完全移除变量

  • 实际应用中常配合条件判断进行选择性删除

三 shell脚本调试

基本调试方法:

1.执行时启用调试模式

# 在命令行执行时启用调试
bash -x script.sh  # 显示所有执行的命令
bash -v script.sh  # 显示原始脚本内容
bash -n script.sh  # 只检查语法不执行

2.脚本内启用调试模式

#!/bin/bash
set -x  # 开启调试
# 脚本内容...
set +x  # 关闭调试

常用调试基本选项:

选项作用描述
set -x打印执行的命令及参数(xtrace)
set -v打印输入的shell命令(verbose)
set -n只读取不执行(语法检查)
set -e命令失败时立即退出(errexit)
set -u使用未定义变量时报错(nounset)
set -o pipefail管道中任一命令失败则整个管道失败

应用示例:

#!/bin/bash
set -euxo pipefail           

# 常用严格模式组合

function divide() {
    local numerator=$1
    local denominator=$2
    echo "DEBUG: numerator=$numerator, denominator=$denominator" >&2
    echo $((numerator / denominator))
}

main() {
    local a=10
    local b=0
    result=$(divide $a $b)
    echo "Result: $result"
}

trap 'echo "Error at line $LINENO"' ERR
main

四 总结

Shell函数
定义func_name() { cmds; } 或 function func_name { cmds; }say_hello() { echo "Hello $1"; }
参数$1-$n 位置参数,$#参数个数,$@所有参数func foo bar → $1=foo$2=bar
返回值return 返回状态码(0-255),echo输出结果return 0 或 echo "result"
局部变量local var=value 限定函数内作用域local count=0
Shell数组
索引数组arr=(val1 val2),下标从0开始colors=("red" "green")${colors[0]} → "red"
关联数组declare -A arr=([k1]=v1 [k2]=v2)(Bash 4.0+)declare -A dict=([name]="Alice")${dict[name]} → "Alice"
常用操作${arr[@]}所有元素,${#arr[@]}长度,${arr[@]:1:2}切片echo "${colors[@]:1}" → "green"
遍历for i in "${arr[@]}"; do ... donefor color in "${colors[@]}"; do echo $color; done
脚本调试
调试模式bash -x script.sh(跟踪执行),set -x(脚本内启用)set -x 和 set +x 包围调试代码块
严格模式set -euo pipefail(错误退出+未定义变量报错+管道失败检测)脚本开头添加增强安全性
调试工具shellcheck(静态检查),bashdb(交互调试),trap(错误捕获)trap 'echo "Error at $LINENO"' ERR
日志输出echo "DEBUG: $var" >&2(输出到标准错误)关键步骤添加变量打印

部分核心关联

  1. 函数+数组:函数内可处理数组参数(func "${arr[@]}"),返回数组需通过echo输出

  2. 脚本+调试:调试时重点关注函数调用栈和数组传递过程

  3. 最佳实践:函数封装数组操作,脚本主流程调用,set -eux全程监控

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值