Linux系统入门第十一章 --Shell编程之函数与数组
一、Shell函数
1、函数的用法
Shell函数可用于存放一系列的指令。在Shell脚本执行的过程中,函数被置于内存中,每次调用函数时不需要从硬盘读取,因此运行的速度比较快。在Shell编程中函数并非是必须的元素,但使用函数可以对程序进行更好的组织。将一些相对独立的代码变成函数,可以提高程序可读性与重用性,避免编写大量重复代码
格式:
function() {代码块
[return x]}function
function | 关键字表示定义一个函数,可以省略 |
{ | 表示函数执行命令的入口,该符号可以与函数名同行也可以在函数名下一行的句首 |
} | 符号表示函数体结束,两个大括号之间{}是函数体 |
代码块 | 可以是任意的 Shell 命令,也可以调用其他函数 |
return | 表示退出函数返回一个退出值,通过返回值判断执行是否成功,也可以使用 exit 终止整个 Shell 脚本 |
Shel1 函数调用的方法为:函数名「参数 1]〔参数 2]
栗子1:两个数求和
#!/bin/bash
#定义 sum 函数
sum() {
read -p "请输入第一个数字:" A
#检查是否为有效数字
if ! [[ $A =~ ^[0-9]+$ ]]
thenecho "这不是一个有效数字,请重新输入"return 1
firead -p "请输入第二个数字:" B
if ! [[ $B =~ ^[0-9]+$ ]]
thenecho "这不是一个有效数字,请重新输入"return 1
fi#计算两数之和
result=$((A + B))
echo "两数之和是:$result"
}
#调用函数
sum
执行结果:
栗子2:监控系统资源
该函数会定期监控系统的 CPU 和内存使用率,当使用率超过设定的值时,会发送报警信息,这里简单模拟为输出到控制台,实际应用中可扩展为发送邮件、短信等。
#!/bin/bash
send_alert() {local message=$1
echo "ALERT:$message"}#系统资源控制函数
monitor_system_resources() {local cpu_threshold=$1
local mem_threshold=$1
local interval=$3while true
do
#获取CPU的使用率
cpu_usage=$(top -bn1 | grep Cpu | awk '{print $2+$4}')
#获取内存使用率
mem_usage=$(free | grep Mem | awk '{print $3/$2 *100}')if (($(echo "$cpu_usage > $cpu_threshold" |bc -l)))
thensend_alert "CUP usage (${cpu_usage}%)"
fiif (($(echo "$mem_usage > $mem_threshold" |bc -l)))
thensend_alert "Mem usage (${mem_usage}%)"
fisleep "$interval"done
}
#调用函数
monitor_system_resources 2 5 2
执行结果:
参数说明:函数接收三个参数,分别是CPU使用率值、内存使用率值以及监控间隔时间(秒)
循环监控:使用 while true 循环不断监控系统资源。通过 top 和 free 命令获取 CPU 和内存使用率,使用 bc 命令进行浮点数比较。
报警处理:当使用率超过阈值时,调用 send alert 函数发送报警信息
2、函数变量的作用范围
在 Shel1 脚本中函数的执行并不会开启一个新的子 Shell,而是仅在当前定义的 shel1 环境中有效。如果 Shel1 脚本中的变量没有经过特殊设定,默认在整个脚本中都是有效的。
在编写脚本时,有时需要将变量的值限定在函数内部,可以通过内置命令 1ocal 来实现。函数内部变量的使用,可以避免函数内外同时出现同名变量对脚本结果的影响。local 命令的使用如下所示。
#!/bin/bash
AAA(){
local i
i=8
echo $i
}
i=9
AAA
echo $i
上述脚本中,AAA 函数内部使用了 local 命令设置变量 i,其作用是将变量 i 限定在函数内部AAA 函数外部同样定义了变量 ,内部变量 i 和全局变量 i 互不影响。脚本执行时先调用了函数AAA,函数内部变量 i 为 8,所以输出结果是 8。调用完函数之后,给变量i 赋值为 9,再打印外部变量 i,所以又输出 9
3、递归函数
Shell 也可以实现递归函数,就是可以调用自己本身的函数。在 Linux 系统上编写shell脚本的时候,经常需要递归遍历系统的目录,列出目录下的文件和目录,逐层递归列出,并对这些层级关系进行展示。具体的实现过程如下所示
#!/bin/bash
#定义递归遍历目录的函数
traverse_directory() {
local dir=$1
#遍历当前目录下所有的目录和文件
for item in "$dir"/*
do if [ -d "$item" ]then
#如果是目录则递归调用函数继续循环echo "这是目录:$item"traverse_directory "$item"elif [ -f "$item" ]then
#如果是文件就输出路径echo "这是文件:$item"fi
done
}
#调用函数
#“.”:当前目录
traverse_directory "."
执行结果:
二、Shell数组
在 shell 脚本中,数组是一种常见的数据结构,主要的应用场景包括:获取数组长度、获取元素长度、遍历元素、元素切片、元素替换、元素删除等等。shell中的数组与 Java、c、Python 不同,只有一维数组,没有二维数组。数组元素的大小与限制,也不需要事先定义。Shell 数组用括号()来表示,元素用空格分隔,元素的下标与大部分编程语言类似从开始。
fruits=("Apple" "Banana" "Cherry") # 元素带空格时必须加引号
nums=(10 20 30) # 数字类型可不加引号
1、获取数组长度
在 shell 编程中,数组是一种用于存储多个值的数据结构。获取数组长度(即数组中元素的个数)在很多场景下都非常有用,比如进行数组遍历、数据处理等。普通数组是 Shell 中最常见的数组类型,其下标是从0 开始的连续整数。获取普通数组长度可以使用 ${#数组名[@]}或 ${#数组名[*]} 这两种语法,它们的效果是一样的。
#定义一个数组A
A=(1 2 3 4 5 6)#打印数组A的长度
#方法一:
echo ${#A[@]}
#方法二:
echo ${#A[*]}
2、读取指定元素对应的值
在 shell 编程里,你可以读取数组中指定下标的元素,也可以给指定下标的数组元素赋值。普通数组是 Shell 中最常用的数组类型,其下标是从0开始的整数
#定义一个数组A
A=(1 2 3 4 5 6)#读取3号元素对应的值
echo ${A[3]}#读取数组中所有的元素值
echo ${A[@]
echo ${A[*]
3、数组遍历
在 Shell 编程里,数组遍历指的是按顺序访问数组中的每一个元素,并对这些元素执行特定操作的过程,这在处理一组相关数据时非常有用,比如批量处理文件、统计数据等
#!/bin/bash
A=("好" "好" "学" "习" "天" "天" "向" "上")
for i in ${A[@]}
do echo $i
done
执行结果:
4、数组切片
数组切片是一种操作,用于从数组中提取出一部分连续的元素,形成一个新的数组。这个操作在很多编程语言中都有支持,不过不同语言实现数组切片的语法和方式会有所差异。在Bash脚本里,也可以进行数组切片操作,语法是${array[@]:start:length},其中start是开始的索引,length是要提取的元素个数
#定义一个数组A
A=(1 2 3 4 5 6)echo ${A[@]}echo ${A[@]:0:5}echo ${A[@]:1:5}
5、数组替换
#定义一个数组A
A=(1 2 3 4 5 6)#打印数组元素对应的值
echo ${A[@]}
#1 2 3 4 5 6#将4号元素对应的值5修改为100
echo ${A[@]/5/100}#将4号元素对应的值6修改为200
echo ${A[@]/6/200}
6、数组删除
#定义一个数组A
A=(1 2 3 4 5 6)#删除数组中的指定的3号元素
unset A[3]#删除数组
unset ${A[*]}
unset A
三、Shell脚本调试
在Shell脚本开发中,经常碰到一些规范方面的问题,例如忘了使用引号或在if语句末尾处忘记加fi结束。要注意把复杂的脚本简单化,要思路清晰,并且分段实现。当执行脚本时出现错误后,不要只看那些提示的错误行,而是要观察整个相关的代码段。
为避免编写的脚本出错,除了在编写脚本时注意书写规范,排除语法错误,更重要的是利用调试脚本工具来调试脚本。echo命令是最有用的调试脚本工具之一,一般在可能出现问题的脚本中加入echo命令,采用的是分段排查的方式
除了echo命令之外,bash Shell也有相应参数可以调试脚本
sh [-nvx] 脚本名
-n | 不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任何内容,如果有问题会提示报错 |
-v | 在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出错误提示 |
-x | 将执行的脚本内容输出到屏幕上,这个是对调试很有用的参数 |
#!/bin/bash
set -x #开启调试
#定义 sum 函数
sum() {
read -p "请输入第一个数字:" A
#检查是否为有效数字
if ! [[ $A =~ ^[0-9]+$ ]]
thenecho "这不是一个有效数字,请重新输入"return 1
firead -p "请输入第二个数字:" B
if ! [[ $B =~ ^[0-9]+$ ]]
thenecho "这不是一个有效数字,请重新输入"return 1
fi
set +x #关闭调试
#计算两数之和
result=$((A + B))
echo "两数之和是:$result"
}
#调用函数
sum
总结:
函数:函数是Shell脚本中组织代码、提高复用性的重要手段。通过将一系列指令封装成函数,可以避免代码重复,使脚本更加简洁易读。函数的定义与调用简单直观,支持参数传递和递归调用,为模块化开发提供了便利。
数组:作为Shell脚本中的一种重要数据结构,数组支持存储多个值,并提供了丰富的操作方法,如获取数组长度、读取和赋值、遍历、切片、替换和删除元素等。这些功能在处理一组相关数据时非常有用。
调试与测试:在Shell脚本编写过程中,调试与测试是确保脚本正确运行的关键环节。通过使用echo命令和bash的调试参数(-n、-v、-x),可以方便地定位和解决问题,提高脚本的稳健性